Тип возвращаемого значения метода интерфейса — класс, реализующий интерфейс.

У меня проблемы с интерфейсами. После изучения подобных вопросов здесь я придумал следующий интерфейс для определения операций CRUD, необходимых для всех моих классов:

public interface IData<T>
{
    IData<T> Select(int id);
    List<T> SelectMultiple();
    void Insert();
    void Update();
    void Delete();
}

Затем это реализуется в моих частичных классах:

public partial class Post : IData<Post>
{
    public IData<Post> Select(int id)
    {
        MyDataContext dc = MyDataContext.Create();
        return dc.Posts.Single(p => p.PostID == id);
    }

    public List<Post> SelectMultiple()
    {
        MyDataContext dc = MyDataContext.Create();
        return dc.Posts.ToList();
    }

    // Update() and Delete() declarations
}

Все это прекрасно компилируется, однако, если я попытаюсь использовать метод Post Select():

Post p = new Post().Select(1);

Ошибка возникает из-за Невозможно неявно преобразовать тип IData в Post. Существует явное преобразование (вам не хватает приведения?)

Это имеет смысл, но как сделать так, чтобы не требовался Cast? Я хочу, чтобы Select возвращал Post (но не определял Post как возвращаемый тип на уровне интерфейса). Я неправильно понял интерфейсы, или я могу быстро внести изменения?


person Lazlow    schedule 28.11.2010    source источник
comment
Кажется, ваш Post смешивает проблемы; он выполняет CRUD, а также занимает пост. Я бы разделил его на два класса, например. Post и PostStorage.   -  person strager    schedule 28.11.2010
comment
Сообщения хранятся в SQL Server и доступны через LinqToSQL DBML. Приведенный выше класс Post является частичным классом Post в DBML.   -  person Lazlow    schedule 28.11.2010


Ответы (4)


Вы хотите вернуть что-то типа T, а не IData<T>, поэтому просто измените подпись (по крайней мере, я думаю, это то, что вы хотите, иначе вы бы вернули List<IData<T>>):

public interface IData<T>
{
  T Select(int id);
  List<T> SelectMultiple();
  void Insert();
  void Update();
  void Delete();
}

и реализовать его соответствующим образом:

public Post Select(int id)
{
    MyDataContext dc = MyDataContext.Create();
    return dc.Posts.Single(p => p.PostID == id);
}

Если вы просто хотите такое поведение в классе Post, явно реализуйте интерфейс IData<T>:

public partial class Post : IData<Post>
{
  public Post Select(int id)
  {
      MyDataContext dc = MyDataContext.Create();
      return dc.Posts.Single(p => p.PostID == id);
  }

  IData<Post> IData<Post>.Select(int id)
  {
      return Select(id);
  }

}
person Femaref    schedule 28.11.2010

Вам нужно изменить методы, чтобы они возвращали Post экземпляров, а затем добавить явные реализации интерфейса, которые возвращают интерфейс.

Например:

public partial class Post : IData<Post> {
    Post Select(int id) { ... }
    IData<Post> IData<Post>.Select(int id) { return Select(id); }
}
person SLaks    schedule 28.11.2010
comment
Это работает, но кажется странным создавать один метод для удовлетворения требований интерфейса, а другой — для реального использования. - person Lazlow; 28.11.2010
comment
@Lazlow, это делается чаще, чем ты думаешь. Например, это очень распространено при реализации IEnumerable<T>; IEnumerable GetEnumerator() просто вызывает IEnumerable<T> GetEnumerator(). - person strager; 28.11.2010

Как насчет попытки

public Post Select(int id)
{
    MyDataContext dc = MyDataContext.Create();
    return dc.Posts.Single(p => p.PostID == id);
}

т. е. возвращать напрямую Post вместо IData<Post>.

person Jon    schedule 28.11.2010
comment
Тогда интерфейс не реализован. - person strager; 28.11.2010
comment
Да, конечно, вам также нужно будет провести рефакторинг. На самом деле ответ SLaks выше - это та же идея, но правильно развитая. - person Jon; 28.11.2010
comment
Вот с чего я начал, но он не скомпилировался, так как подпись не соответствовала подписи интерфейса. - person Lazlow; 28.11.2010

Вы должны явно реализовать IData<Post>.Select и предоставить свой собственный Select с соответствующим возвращаемым значением. Например:

IData<Post> IData<Post>.Select(int id)
{
    return Select(id);
}

Post Select(int id)
{
    MyDataContext dc = MyDataContext.Create();
    return dc.Posts.Single(p => p.PostID == id);
}

Однако, если вы сделаете это:

IData<Post> post = new Post();
Post p = post.Select(1);

post.Select(1) по-прежнему возвращает IData<Post>. См. ответ Femaref по рефакторингу интерфейса, чтобы разрешить это.

person strager    schedule 28.11.2010