Почему список интерфейсов не может использовать тип реализации? - PullRequest
7 голосов
/ 31 октября 2010

Должно быть что-то фундаментальное в интерфейсах / обобщениях, которые я еще не изучил. Я надеюсь выучить это сейчас.

Вот сценарий:

У меня есть этот интерфейс и класс:

public interface IInterface
{
    string TestValue { get; set; }
}

public class RealValue: IInterface
{
    public string TestValue { get; set; }
}

Если я создаю такой метод, он прекрасно компилируется:

public class RandomTest: IMethodInterface
{
   public IInterface GetRealValue()
   {
       RealValue realValue = new RealValue();
       return realValue;
   }
 }

Обратите внимание, что я возвращаю объект, который реализует интерфейс.

Теперь, если я добавлю в класс RandomTest метод, который возвращает список, он больше не будет работать:

 public List<IInterface> GetRealValues()
 {
    List<RealValue> realValues = new List<RealValue>();
    return realValues;  // ERROR Here <- says it can't convert to a List<IInterface>
 }

Итак, я думаю, что дженерики не могут этого понять, но почему?

Есть ли способ обойти это? Что вы делаете, когда возвращаемое значение описанного выше метода заблокировано, потому что вы реализуете такой интерфейс:

public interface IMethodInterface
{
    IInterface GetRealValue();
    List<IInterface> GetRealValues(); // Can't just convert the return types to a concrete 
                                      // class because I am implementing this.  This 
                                      // interface is in a separate project that does not 
                                      // have the concrete classes.
}

Есть ли надежда? Что бы вы сделали?

Ответы [ 3 ]

10 голосов
/ 31 октября 2010

Причина этого в том, что List<RealValue> - это определенный тип, который не наследует List<IInterface>, поэтому его нельзя преобразовать.

Однако в .NET 4.0 вам повезло.Интерфейс IEnumerable<out T> указывает, что T может быть классом или базовым классом, поэтому вы можете изменить свой метод на:

IEnumerable<IInterface> GetRealValues();

в .NET 4.0.Обратите внимание, что это работает только потому, что IEnumerable имеет ключевое слово out, указанное в параметре шаблона.

Ключевое слово out означает две вещи:

  1. Типперед которым вы ставите ключевое слово out, может использоваться только для типов, которые выходят из класса.Так, public T MyMethod() разрешено, но public void MyMethod(T myParam) не разрешено, потому что это входит в класс;

  2. Из-за этого ограничения .NET знает, что T может быть обработаноко всему, что наследуется от T.Из-за ограничения это гарантированно безопасная операция.

3 голосов
/ 31 октября 2010

Обратите внимание, что если бы вы могли преобразовать List<RealValue> в List<IInterface>, вы могли бы позвонить .Add(anyObjectImplementingIInterface), который не может работать.

Однако вы можете использовать .Cast<IInterface>().ToList().

1 голос
/ 31 октября 2010

A List<RealValue> нельзя использовать вместо List<IInterface>.Если бы это было разрешено, вызывающая сторона могла бы добавить IInterface в возвращаемый список, который имеет тип, отличный от RealValue.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...