4

来自 Java 世界,使用泛型和 C# 进行编程常常令人头疼。像这个:

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());
    }
}

结果是InvalidCastExceptionat Something = (ISomething<ISomeObject>)s;。在 Java 中,这会起作用,我什至可以使用(如果一切都失败了)泛型通配符<?>。这在 C# 中是不可能的。

虽然这只是我用来解释问题的一个例子,但是如何消除这个异常呢?唯一的主要约束是SomeContainer 不能是泛型类

**注意**:关于这个有很多问题,但没有一个(我能找到)解决非泛型类中的泛型类成员。

**更新**

在方法内部SetSomething,我添加了以下几行:

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());
}

令我惊讶的输出

False
SomeThingA : System.Object
ISomething`1[SomeObjectA]

这就是我得到这个例外的原因吗?

4

2 回答 2

5

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

interface ISomething<out T> where T : ISomeObject

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

它被称为协方差和逆变

Eric Lippert 有一个很好的系列文章为什么我们需要考虑这个,这里使用接口方差

这是我的代码,它按预期工作

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());
    }
}
于 2012-11-29T15:35:18.533 回答
2

有时让一个泛型接口实现一个非泛型接口来规避缺失是很有用的<?>

interface ISomething
{
    object GetObject();
}

interface ISomething<T> : ISomething
    where T : ISomeObject
{
    T GetObject();
}

public class SomeImplementation<T> : ISomething<T>
{
    public T GetObject()
    {
        ...
    }

    object ISomething.GetObject()
    {
        return this.GetObject(); // Calls non generic version
    }
}

然后可以使用非泛型接口键入集合

var list = new List<ISomething>();
list.Add(new SomeImplementation<string>());
list.Add(new SomeImplementation<int>());
于 2012-11-29T15:47:36.143 回答