在C#中向通用列表中添加通用对象

13

我有一个类,其中相关部分如下:

class C {
    void Method<T>(SomeClass<T> obj) {
        list.Add(obj);
    }
    List<?> list = new List<?>();
}

如何定义一个列表以便类编译通过?

我想要一个类型为List<SomeClass<?>>的列表,即一个由SomeClass对象组成的列表,每个对象都可以有任何类型的参数。Java中的?构造允许这样做;在C#中有相应的等价物吗?如果没有,是否有合适的解决方法?(List<object>可以实现,但非常丑陋。)


请问您能否详细说明通过“Method”函数您期望添加哪些类型的项目? - el2iot2
啊,算了,我在注释里看到了。 - el2iot2
在c# 4.0中,您可以将SomeClass声明为dynamic而不使用泛型。然后列表变为List<SomeClass>。 - Goran
5个回答

14
我不认为你可以在C#中这样做...你需要向类添加类型参数:

class C<T> {
    void Method(SomeClass<T> obj) {
        list.Add(obj);
    }
    List<SomeClass<T>> list = new List<SomeClass<T>>();
}

另一个选择是使用接口:
class C {

    void Method<T>(T obj)
         where T : ISomeClass {
        list.Add(obj);
    }
    List<ISomeClass> list = new List<ISomeClass>();
}

我认为这更符合我理解提问者所询问的精神(接口版本)。基本上,它是一个“部分已知”项目列表,但不仅仅是“List<object>”。 - el2iot2
1
谢谢您的帮助。所以stackoverflow让我编辑我的问题...但是有没有办法将您的答案与下面添加关于C#中我想要的不可能性的额外信息的答案结合起来? - errcw
@errcw 我可以编辑它,或者任何拥有2k+声望的人都可以...你想要什么具体信息? - Daniel Schaffer
Mehrdad在C# 3/4的技术说明中简单地指出:“不幸的是,由于泛型是不变的,所以在C# 3.0中没有直接等价物。但是,您可以使用C# 4.0的安全协变/逆变特性以一种优雅的方式完成类似操作。” - errcw

3

要实现你想要的功能,你有两个选项。

你可以使用List<object>并处理对象。这样做不会具备类型安全性,并且对于值类型会存在装箱/拆箱问题,但它可以工作。

另一个选择是使用泛型约束来限制基类或接口,并使用List<Interface>。


2

我不了解Java中的?结构,但我认为以下内容最接近于保留您现有语法并匹配您的描述。

    class SomeClass<T>
    {
    }

    class C
    {
        void Add<T>(SomeClass<T> item)
        {
            Type type = typeof(SomeClass<T>);
            if (!list.ContainsKey(type))
                list[type] = new List<SomeClass<T>>();
            var l = (List<SomeClass<T>>)list[type];
            l.Add(item);
        }

        public void Method<T>(SomeClass<T> obj)
        {
            Add(obj);
        }
        readonly Dictionary<Type, object> list = new Dictionary<Type, object>();
    }

请使用以下方式进行测试:

    class Program
    {
        static void Main(string[] args)
        {
            var c = new C();
            var sc1 = new SomeClass<int>();
            var sc2 = new SomeClass<String>();
            c.Method(sc1);
            c.Method(sc2);
            c.Method(sc1);
            c.Method(sc2);
        }
    }

2

很遗憾,由于泛型是不变的,所以在C# 3.0中没有直接等效的方法。使用C# 4.0的安全协变/逆变功能,您可以优雅地执行类似于以下操作。

为了解决这个问题,您可以从非泛型基类继承SomeClass<T>并创建一个List<BaseClass>。如果该类的每个实例只应保存一种类型,则可以使类本身成为通用的,并在那里设置类型参数。


谢谢你的BaseClass提示,当你想要模拟Java通配符时确实非常有用。 - Vincent B.

0

个人而言,如果可能的话,我会将泛型参数从方法移动到类中。

class C<T> {
    void Method(SomeClass<T> obj) {
        list.Add(obj);
    }
    List<?> list = new List<?>();
}

如果您的泛型列表是一个成员,那么构造类时应该考虑到这一点。没有更多关于该类的使用上下文,我们很难建议最佳模式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接