泛型上的InvalidCastException [英] InvalidCastException on Generics

查看:88
本文介绍了泛型上的InvalidCastException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从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]

这就是为什么我得到这个异常的原因吗?

解决方案

Out 关键字将是一个修复,如果您的 ISomething 只有返回T的方法

  interface ISomething< out T>其中T:ISomeObject 

在创建通用接口时,可以指定接口之间是否存在隐式转换实例有不同类型的参数。



它被称为协方差和反变换



Eric Lippert有一个很好的 interface差异被使用



这里是我的代码,它对我的​​预期工作

 接口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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆