Компилятор C # не может распознать класс, реализующий интерфейс - PullRequest
12 голосов
/ 20 мая 2010

Следующий код не компилируется (с использованием 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
    }
}

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

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

  2. Аргумент 1: невозможно преобразовать из 'System.Collections.Generic.List ' в 'System.Collections.Generic.IEnumerable '

Ответы [ 3 ]

8 голосов
/ 20 мая 2010

То, что вы пытаетесь сделать, называется ковариация - преобразование из более узкого типа (TestClass) в более широкий тип (ITest). Это то, к чему вы будете привыкать все время, например, когда вы конвертируете из числа с плавающей точкой в ​​двойное

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

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

public interface IEnumerable<out T> : IEnumerable

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

MSDN имеет больше информации .

2 голосов
/ 20 мая 2010

Это связано с дисперсией (ковариация и контравариантность); проверьте этот пост и ответ Джона Скита

1 голос
/ 20 мая 2010

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

...