Общие ограничения и реализация интерфейса/наследование

Не совсем уверен, как сформулировать вопрос, потому что это "почему это не работает?" тип запроса.

Я уменьшил свою конкретную проблему до этого кода:

public interface IFoo
{
}

public class Foo : IFoo
{
}

public class Bar<T> where T : IFoo
{
    public Bar(T t)
    {
    }

    public Bar()
        : this(new Foo()) // cannot convert from 'Foo' to 'T'
    {
    }
}

Теперь общий тип T в классе Bar<T> должен реализовать IFoo. Итак, почему компилятор дает мне ошибку в комментарии? Разумеется, экземпляр Foo является IFoo и поэтому может быть передан как представитель типичного типа T?

Является ли это компилятором или мне что-то не хватает?

Ответы

Ответ 1

У вас также может быть Fiz, который реализует IFoo, который не связан с Foo любым другим способом:

public interface IFoo
{
}

public class Foo : IFoo
{
}

public class Fiz : IFoo
{
}

Foo foo = new Foo();
Fiz fiz = foo; // Not gonna compile.

То, что вы хотите, вероятно, больше похоже на:

public class Bar<T> where T : IFoo, new()
{
    public Bar(T t)
    {
    }

    public Bar()
        : this(new T()) 
    {
    }
}

Итак, вы можете иметь

Bar<Foo> barFoo = new Bar<Foo>();
Bar<Fiz> barFiz = new Bar<Fiz>();

Ответ 2

Если вы создадите класс Baz, а затем общий тип Bar baz = new Bar(), новый Foo(), определенный как перегрузка вашего конструктора, не будет иметь тип T, в данном случае Baz.

Ответ 3

Это потому, что если вы создаете класс:

public class Fred : IFoo
{
}

И затем создайте экземпляр Bar<T> следующим образом:

var bar = new Bar<Fred>();

Затем он нарушает ограничения класса, поскольку Foo не является Fred, который является текущим T.

Вы можете заставить его скомпилировать, поместив последовательность cast (T)(IFoo)new Foo() в конструктор, но во время выполнения вы получите InvalidCastException, если фактический тип T не может быть назначен из Foo.