简体   繁体   English

使用接口转换为泛型类

[英]Casting to a generic class with interface

Updated with input from MarcinJuraszek 更新了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; }
}

and I have a class that implements IMyInterface 我有一个实现IMyInterface的类

public class MyImplementation : IMyInterface
{

}

And, of course, I have a class with a SomeClass property: 当然,我有一个带有SomeClass属性的类:

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

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> . 现在我的问题是我无法将SomeClass<MyEnum, MyImplementation>分配给MyProp属性,因为我在运行时收到InvalidCastException ,抱怨它无法将SomeClass<MyEnum, MyImplementation> InvalidCastExceptionSomeClass<MyEnum, MyImplementation> SomeClass<MyEnum, IMyInterface>

How do I work around this? 我该如何解决这个问题?

Example, this doesn't compile: 例如,这不编译:

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

Here's a dot net fiddle 这是一个小点网小提琴

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: 但是,在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; }
}

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: 另一种可能的解决方案是使用另一个接口,其中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; }
}

Bonus - as of why it doesn't work: 奖金 - 为什么它不起作用:

Let's imagine that your code compiles, and you can assign MyClass<T> to MyClass<IT> as long as T implements IT . 让我们假设您的代码编译,只要T实现IT ,您就可以将MyClass<T>分配给MyClass<IT> You could have following class: 你可以有以下课程:

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

And do 并做

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

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. 使用该instance.MyProp List<MyInterfaceImplementation>将是List<MyInterfaceImplementation>但您可以访问它,就像它是List<IMyInterface>因此您可以尝试添加MyOtherInterfaceImplementation元素,这会在运行时崩溃。 Not fun. 不好玩。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM