使用接口转换为泛型类

时间:2015-01-12 21:16:37

标签: c# generics covariance

根据MarcinJuraszek

的输入进行了更新

我有一种感觉,我在这里碰到了一个共同/逆向差异问题,但我不确定我是否理解如何修复它。我有一个这样的课:

public interface ISomeClass<TEnum, out S>
{
     TEnum Dim { get; }
     IEnumerable<S> Inc { get; }
}

public class SomeClass<TEnum, S> : ISomeClass<TEnum, S>
    where TEnum : struct, IConvertible
    where S : IMyInterface
{
    public TEnum Dim { get; set; }
    public IEnumerable<S> Inc { get; set; }
}

我有一个实现IMyInterface

的类
public class MyImplementation : IMyInterface
{

}

当然,我有一个SomeClass属性的课程:

public class MyContainer<TEnum> where TEnum : struct, IConvertible
{
    public SomeClass<TEnum, IMyInterface> MyProp { get; set; }
}

现在我的问题是,我无法将SomeClass<MyEnum, MyImplementation>分配给MyProp属性,因为我在运行时收到InvalidCastException抱怨它无法投放SomeClass<MyEnum, MyImplementation>SomeClass<MyEnum, IMyInterface>

我该如何解决这个问题?

示例,这不会编译:

var c = new MyContainer<MyEnum>();
c.MyProp = new SomeClass<MyEnum, MyImplementation>();

这里是dot net fiddle

1 个答案:

答案 0 :(得分:4)

您可以通过使您的泛型类型参数不变(协变或逆变,取决于其成员)来使其工作。但是,在C#中,您只能声明接口上的泛型参数不变,因此您必须声明另一个接口:

public interface ISomeClass<TEnum, in S>
{

}

public class SomeClass<TEnum, S> : ISomeClass<TEnum, IMyInterface>
    where TEnum : struct, IConvertible
    where S : IMyInterface
{

}

public class MyContainer<TEnum> where TEnum : struct, IConvertible
{
    public ISomeClass<TEnum, IMyInterface> MyProp { get; set; }
}

这将使以下代码编译:

var container = new MyContainer<DayOfWeek>();
container.MyProp = new SomeClass<DayOfWeek, MyImplementation>();

另一种可能的解决方案是使用另一个接口,其中S泛型类型参数不存在:

public interface ISomeClass<TEnum>
    where TEnum: struct, IConvertible
{

}

public class SomeClass<TEnum, S> : ISomeClass<TEnum>
    where TEnum : struct, IConvertible
    where S : IMyInterface
{

}

public class MyContainer<TEnum> where TEnum : struct, IConvertible
{
    public ISomeClass<TEnum> MyProp { get; set; }
}

奖金 - 至于其无效的原因:

让我们假设您的代码已编译,只要MyClass<T>实现MyClass<IT>,您就可以将T分配给IT。你可以拥有以下课程:

class MyClass<T>
{
    public List<T> MyProp { get; set; }
}

并且

MyClass<IMyInterface> instance = new MyClass<MyInterfaceImplementation>();

instance.MyPropList<MyInterfaceImplementation>,但您可以访问List<IMyInterface>,因此您可以尝试添加MyOtherInterfaceImplementation的元素,这会在运行时崩溃。不好玩。