铸造用接口的通用类 [英] Casting to a generic class with interface
问题描述
与输入更新从MarcinJuraszek
我有一种感觉,我碰到一个合作/潮水变化问题就在这里,但我不能确定我知道如何解决它。我有这样一个类:
I have a feeling I'm bumping into a co / contra variance problem here, but I'm not sure I understand how to fix it. I have a class like this:
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的$ C类$ C>属性:
And, of course, I have a class with a SomeClass
property:
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的>
。
Now my problem is that I can't assign a SomeClass<MyEnum, MyImplementation>
to the MyProp
property because I get an InvalidCastException
at runtime complaining that it can't cast the SomeClass<MyEnum, MyImplementation>
to SomeClass<MyEnum, IMyInterface>
.
我要如何解决这个
例,这并不编译:
var c = new MyContainer<MyEnum>();
c.MyProp = new SomeClass<MyEnum, MyImplementation>();
下面是一个的点网小提琴
推荐答案
您可以把它通过让您的工作泛型类型参数不变的(无论是协变或逆变,这取决于它的成员)。然而,在C#中你只能声明接口不变泛型参数,所以你必须声明另一个接口:
You can make it work by having your generic type parameter invariant (either covariant or contravariant, depending on its members). However, in C# you can only declare generic parameters invariant on interface, so you'd have to declare another interface:
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; }
}
这会使下面的代码编译:
That would make following code compile:
var container = new MyContainer<DayOfWeek>();
container.MyProp = new SomeClass<DayOfWeek, MyImplementation>();
另一种可能的解决方案将是使用另一个接口,其中取值
泛型类型参数不存在:
Another possible solution would be to use another interface, where S
generic type parameter doesn't exist:
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; }
}
奖金 - 因为它为什么没有按' ŧ工作:
Bonus - as of why it doesn't work:
让我们想象一下,你的代码编译,并且你可以将 MyClass的< T>
到 MyClass的< IT>
只要 T
工具 IT
。你可以有下面的类:
Let's imagine that your code compiles, and you can assign MyClass<T>
to MyClass<IT>
as long as T
implements IT
. You could have following class:
class MyClass<T>
{
public List<T> MyProp { get; set; }
}
和做
MyClass<IMyInterface> instance = new MyClass<MyInterfaceImplementation>();
与 instance.MyProp
是列表< MyInterfaceImplementation>
,但你有机会访问它,就好像它是列表< IMyInterface的>
所以你可以尝试添加的元素 MyOtherInterfaceImplementation
将导致程序崩溃在运行时。不好玩。
with that instance.MyProp
would be List<MyInterfaceImplementation>
but you had access to it as if it was List<IMyInterface>
so you could try adding element of MyOtherInterfaceImplementation
which would crash at runtime. Not fun.
这篇关于铸造用接口的通用类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!