问题描述
从Java世界开始,泛型和C#编程经常令人头疼。像这样:$ $ p $接口ISomeObject {
类SomeObjectA:ISomeObject {}
类SomeObjectB:ISomeObject {}
interface ISomething< T>其中T:ISomeObject
{
T GetObject();
}
class SomethingA:ISomething< SomeObjectA>
{
public SomeObjectA GetObject(){return new SomeObjectA(); }
}
class SomethingB:ISomething< SomeObjectB>
{
public SomeObjectB GetObject(){return new SomeObjectB(); }
}
类SomeContainer
{
private ISomething< ISomeObject>东西;
public void SetSomething< T>(ISomething< T> s)其中T:ISomeObject
{
Something =(ISomething< ISomeObject>)s;
$ b class TestContainerSomething
{
static public Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething< SomeObjectA>(new SomethingA());
$ / code>
其结果为 InvalidCastException at Something =(ISomething< ISomeObject>)s; 。在Java中,这是可行的,我甚至可以使用泛型通配符<?> 。这在C#中是不可能的。
虽然这只是我解释有问题的一个例子,但如何消除这种例外情况?唯一的主要限制是 SomeContainer 不能是一个泛型类
** Note **:有很多关于这个的问题,但是他们都没有(我能找到)在非泛型类中寻址泛型类成员。
** 更新 **
在方法 SetSomething 这些行:
Console.WriteLine(s.GetType()。IsSubclassOf(typeof(ISomething< SomeObjectA>)));
Console.WriteLine(s.GetType()。ToString()+:+ s.GetType()。BaseType.ToString());
foreach(var in s.GetType()。GetInterfaces())
{
Console.WriteLine(i.ToString());
}
这令我惊喜输出
False
SomeThingA:System.Object
ISomething`1 [SomeObjectA]
这就是为什么我得到这个异常的原因吗?
关键字将是一个修复,如果您的 ISomething 只有返回T的方法
interface ISomething< out T>其中T:ISomeObject
在创建通用接口时,可以指定接口之间是否存在隐式转换实例有不同类型的参数。
它被称为
Eric Lippert有一个很好的被使用
这里是我的代码,它对我的预期工作
接口ISomeObject {}
类SomeObjectA:ISomeObject {} $ b $ class SomeObjectB:ISomeObject {}
interface ISomething< out T>其中T:ISomeObject
{
T GetObject();
}
class SomethingA:ISomething< SomeObjectA>
{
public SomeObjectA GetObject(){return new SomeObjectA(); }
}
class SomethingB:ISomething< SomeObjectB>
{
public SomeObjectB GetObject(){return new SomeObjectB(); }
}
类SomeContainer
{
private ISomething< ISomeObject>东西;
public void SetSomething< T>(ISomething< T> s)其中T:ISomeObject
{
Something =(ISomething< ISomeObject>)s;
$ b class TestContainerSomething
{
static public Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething< SomeObjectA>(new SomethingA());
}
}
Coming from the Java world, programming with generics and C# is often a headache. Like this one:
interface ISomeObject { } class SomeObjectA : ISomeObject { } class SomeObjectB : ISomeObject { } interface ISomething<T> where T : ISomeObject { T GetObject(); } class SomethingA : ISomething<SomeObjectA> { public SomeObjectA GetObject() { return new SomeObjectA(); } } class SomethingB : ISomething<SomeObjectB> { public SomeObjectB GetObject() { return new SomeObjectB(); } } class SomeContainer { private ISomething<ISomeObject> Something; public void SetSomething<T>(ISomething<T> s) where T : ISomeObject { Something = (ISomething<ISomeObject>)s; } } class TestContainerSomething { static public void Test() { SomeContainer Container = new SomeContainer(); Container.SetSomething<SomeObjectA>(new SomethingA()); } }
Which results into an InvalidCastException at Something = (ISomething<ISomeObject>)s;. In Java, this would work, and I could even use (if all else fails) the generics wildcard <?>. This is not possible in C#.
While this is just an example that I put together to explain the problematic, how can this exception be eliminated? The only main constraint is that SomeContainer cannot be a generic class
** Note ** : there are many questions about this, but none of them (that I could find) address a generic class member inside a non generic class.
** Update **
Inside the method SetSomething, I added these lines :
Console.WriteLine(s.GetType().IsSubclassOf(typeof(ISomething<SomeObjectA>))); Console.WriteLine(s.GetType().ToString() + " : " + s.GetType().BaseType.ToString()); foreach (var i in s.GetType().GetInterfaces()) { Console.WriteLine(i.ToString()); }
which to my surprise output
False SomeThingA : System.Object ISomething`1[SomeObjectA]
Is this why I get this exception?
Out keyword will be a fix, if your ISomething only have methods that return T
interface ISomething<out T> where T : ISomeObject
when creating a generic interface, you can specify whether there is an implicit conversion between interface instances that have different type arguments.
It is called Covariance and Contravariance
Eric Lippert have a good series of articles why we need to think about this, here interface variance is used
Here is my code, which works as expected for me
interface ISomeObject { } class SomeObjectA : ISomeObject { } class SomeObjectB : ISomeObject { } interface ISomething<out T> where T : ISomeObject { T GetObject(); } class SomethingA : ISomething<SomeObjectA> { public SomeObjectA GetObject() { return new SomeObjectA(); } } class SomethingB : ISomething<SomeObjectB> { public SomeObjectB GetObject() { return new SomeObjectB(); } } class SomeContainer { private ISomething<ISomeObject> Something; public void SetSomething<T>(ISomething<T> s) where T : ISomeObject { Something = (ISomething<ISomeObject>)s; } } class TestContainerSomething { static public void Test() { SomeContainer Container = new SomeContainer(); Container.SetSomething<SomeObjectA>(new SomethingA()); } }
这篇关于泛型上的InvalidCastException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!