Подтвердить что ты не робот

Компилятор С# не распознает класс, реализующий интерфейс

Следующий код не удается скомпилировать (используя VS2010), и я не понимаю, почему. Компилятор должен иметь возможность сделать вывод, что List<TestClass> является "совместимым" (извините за отсутствие лучшего слова) с помощью IEnumerable<ITest>, но почему-то это не так. Что мне здесь не хватает?


interface ITest {
    void Test();
}


class TestClass : ITest {
    public void Test() {
    }
}

class Program {
    static void Test(IEnumerable<ITest> tests) {
        foreach(var t in tests) {
            Console.WriteLine(t);
        }
    }
    static void Main(string[] args) {
        var lst = new List<TestClass>();

        Test(lst); // fails, why?

        Test(lst.Select(t=>t as ITest)); //success

        Test(lst.ToArray()); // success
    }
}

Компилятор дает две ошибки:

  • Наилучшее перегруженное соответствие метода для 'ConsoleApplication1.Program.Test(System.Collections.Generic.IEnumerable < ConsoleApplication2.ITest > )' имеет некоторые недопустимые аргументы

  • Аргумент 1: невозможно преобразовать из 'System.Collections.Generic.List < ConsoleApplication2.TestClass > ' to 'System.Collections.Generic.IEnumerable < ConsoleApplication2.ITest > '

4b9b3361

Ответ 1

То, что вы пытаетесь сделать, называется covariance - преобразование из более узкого типа (TestClass) в более широкий тип (ITest). Это то, что вы будете использовать все время, это происходит, если вы, например, конвертируете из float в double.

К сожалению. 3.5 и ниже не поддерживает ковариацию в родовых классах.

.Net 4.0 теперь поддерживает ковариацию (и контравариантность) в generics, если эти общие классы скомпилированы с ключевыми словами out для ковариантных типов и in для контравариантных типов. IEnumerable в .Net 4.0 определяется как ковариантный. Если вы щелкните правой кнопкой мыши по типу IEnumerable и нажмите "определение goto", вы увидите следующее:

public interface IEnumerable<out T> : IEnumerable

Если вы используете VS2010, вам нужно убедиться, что ваш проект нацелен на .net 4.0. Это можно изменить из свойств проекта. Щелкните правой кнопкой мыши по проекту, выберите свойства, перейдите на вкладку "Приложение" и убедитесь, что "Целевая структура" предназначена для .Net 4.

MSDN имеет более подробную информацию.

Ответ 2

Это связано с дисперсией (ковариация и контравариантность); прочитайте этот пост и ответ Jon Skeet

Ответ 3

Проверьте целевую версию фреймворка для своего проекта. Этот код будет работать только в .NET 4.