1

我正在尝试将 Java 代码转换为 C#,但在泛型转换时遇到了问题。

我有一个名为 Copyable 的接口类型,它公开了以下方法......

interface Copyable { void copyTo(Copyable target); }

还有一个 AtomicObject 类型,它以一个泛型类型作为参数,该泛型类型被限制为实现 Copyable 接口......

class AtomicObject<T> where T : class, Copyable {
    public T openRead();

我将 AtomicObjects 存储在对象类型的字典中,但我需要将对象转换回 AtomicObjects 以调用特定于 AtomicObject 类的“openRead”方法......

foreach (KeyValuePair<object, object> entry in dict)
{
    AtomicObject<Copyable> obj = (AtomicObject<Copyable>)entry.Key;
    Copyable dest = (Copyable)obj.openRead();//get the destination
}

我已经实现了一个 ListNode 类型,它扮演 AtomicObject 参数的角色......

class ListNode<T> : Copyable
AtomicObject<ListNode<string>> atomic = new AtomicObject<ListNode<string>>();

我可以编译这段代码,但是当我运行这个程序时,它会产生一个“InvalidCastException”,因为运行时系统无法转换类型的对象......

AtomicObject<ListNode<string>> 

到...

AtomicObject<Copyable>. 

然而 ListNode 是 Copyable 类型的。谁能解释为什么不能正确转换?最重要的是,任何人都可以建议一个不依赖于字典或 foreach 循环的修复,而必须知道 ListNode 包含什么类型的参数?例如,在 Java 中,我可以做到...

AtomicObject<?> obj = (AtomicObject<?>)entry.Key;

但这在 C-Sharp 中是不可能的。

4

2 回答 2

3

您将无法做到这一点,因为您需要协变,而类不能是协变的。

所以你必须从你的AtomicObject

interface IAtomicObject<out T> where T : class, Copyable
{
    public T openRead();
}

(请out在泛型声明中注明),并让您的AtomicObject类实现它。

之后,您应该能够运行以下代码

foreach (KeyValuePair<object, object> entry in dict)
{
    IAtomicObject<Copyable> obj = (IAtomicObject<Copyable>)entry.Key;
    Copyable dest = obj.openRead();
}

另请注意,.net 标准建议在接口名称前加上 I。

于 2012-07-30T14:01:52.717 回答
0

您遇到的问题是由于泛型在 C# 与 Java 中的实现方式不同。Java 使用类型擦除来实现泛型——也就是说, an在运行时AtomicObject<Anything>实际上是 a 。AtomicObject<Object>在 C# 中,情况并非如此——泛型是使用具体类型实现的,因此在运行时维护它们的类型参数化。在 C# 中, anAtomicObject<Whatever>始终是AtomicObject<Whatever>,而永远不是 an AtomicObject<SomethingElse>(除非 AtomicObject 是接口 - 请参阅泛型变体)。

您可以做的是对包含循环的方法进行类型参数化:

(注意- C# 中的接口按照惯例应以大写 I 开头。我已将您的 Copyable 重命名为这样)

我认为以下应该做你所追求的。注意我已经注意测试了这段代码:

public void DoSomething<TObj>(IEnumerable<AtomicObject<TObj>, Object> dict) 
    where TObj : ICopyable {
    foreach (KeyValuePair<AtomicObject<TObj>, Object> entry in dict)
    {
        ICopyable dest = entry.Key.openRead();
        // Whatever...
    }
}
于 2012-07-30T14:02:43.230 回答