代码之家  ›  专栏  ›  技术社区  ›  Jeremy

泛型类型集合

  •  28
  • Jeremy  · 技术社区  · 15 年前

    如果我有一个通用类:

    public class MyClass<T> 
    {
      public T Value;
    }
    

    我想实例化几个项目,例如…

    new MyClass<string>
    new MyClass<int>
    

    …并将它们添加到集合中。如何定义集合以便它可以保存泛型类型列表?然后我想在某个点迭代集合,并使用value属性。可能吗?

    9 回复  |  直到 12 年前
        1
  •  29
  •   Dan Tao    15 年前

    让泛型类从非泛型基继承,或实现非泛型接口。然后,您可以拥有这种类型的集合,并在用于访问集合内容的任何代码中进行强制转换。

    下面是一个例子。

    public abstract class MyClass
    {
        public abstract Type Type { get; }
    }
    
    public class MyClass<T> : MyClass
    {
        public override Type Type
        {
            get { return typeof(T); }
        }
    
        public T Value { get; set; }
    }
    
    // VERY basic illustration of how you might construct a collection
    // of MyClass<T> objects.
    public class MyClassCollection
    {
        private Dictionary<Type, MyClass> _dictionary;
    
        public MyClassCollection()
        {
            _dictionary = new Dictionary<Type, MyClass>();
        }
    
        public void Put<T>(MyClass<T> item)
        {
            _dictionary[typeof(T)] = item;
        }
    
        public MyClass<T> Get<T>()
        {
            return _dictionary[typeof(T)] as MyClass<T>;
        }
    }
    
        2
  •  8
  •   Rob    15 年前

    我能想到的唯一方法是,从我的头顶上看,如下(包裹在一个控制台应用程序中进行测试):

    class Program
    {
        static void Main(string[] args)
        {
            var x = new MyClass<string>() { Value = "34" };
            var y = new MyClass<int>() { Value = 3 };
    
            var list = new List<IMyClass>();
            list.Add(x);
            list.Add(y);
    
            foreach (var item in list)
            {
                Console.WriteLine(item.GetValue);
            }
        }
    
        private interface IMyClass
        {
            object GetValue { get; }
        }
    
        private class MyClass<T> : IMyClass
        {
            public T Value;
    
            public object GetValue
            {
                get
                {
                   return Value;
                }
            }
        }
    }
    

    也就是说,让MyClass实现一个空接口,然后将您的集合创建为包含实现该接口的类实例的集合。

    更新: 我在接口中添加了一个“getValue”方法,允许您作为对象访问myClass实例的“value”。如果你想拥有一个可以容纳混合类型的集合,那么这个集合就和它将要得到的一样好。

        3
  •  3
  •   Josh E    15 年前

    您需要为MyClass定义一个基类,然后您的集合将是一个基类列表。前任:

    void Main()
    {
     var a = new MyClass<string>();
     var b = new MyClass<int>();
     var c = new List<MyBase>();
     c.Add(a);
     c.Add(b);
    
    }
    
    public class MyBase { }
    // Define other methods and classes here
    public class MyClass<T> : MyBase {
    public T Value { get; set;}
    }
    
        4
  •  3
  •   Stefan Steinegger    15 年前

    我的大多数泛型类型上都有与“非类型化”成员的接口:

    private interface IMyClass
    {
        object UntypedValue { get; }
    }
    
    private class MyClass<T> : IMyClass
    {
        T Value { get; set; }
    
        object UntypedValue { get { return Value; } }
    }
    

    您也可以通过使用显式接口实现来实现这一点,但在我看来,使用单独的名称要容易得多。(还有一些关于显式接口实现的CA提示)

        5
  •  3
  •   David Nelson    15 年前

    您希望有一个MyClass集合,对于该集合,类型参数t的值在每个实例中都是不同的。在.NET中,这是不可能的;它缺少等价于Java通配符(?)。您需要做的是创建一个非泛型基类或接口,MyClass可以实现它。例如:

    public interface IMyClass {
      object Value { get; set; }
    }
    public class MyClass<T> : IMyClass {
      public T Value { get; set; }
      object IMyClass.Value {
        get { return Value; }
        set { Value = (T)value; }
      }
    }
    List<IMyClass> m = new List<IMyClass> { new MyClass<string>(), new MyClass<int> };
    
        6
  •  2
  •   Community CDub    8 年前

    我认为这里的问题是泛型类实际上根本不是同一类型。它们只是在编译时创建整个新类型的模板(如果我理解正确的话)。因此, MyClass<int> MyClass<string> 完全地 根据运行时的不同类型。他们也可能是 MyIntClass MyStringClass 很明显,如果不先将它们装箱,就不能将它们放在同一个列表中。它们不(必然)继承相同的基类、实现相同的接口或其他任何东西。它们和其他两种类型一样不同,你必须这样对待它们(即使你认为你知道得更好)。

    当然,您可以让它们实现一个接口、继承一个基对象或任何其他已经给出的选项。看一看 commongenius' answer 为了一个好方法。

        7
  •  2
  •   ΩmegaMan    12 年前

    自.NET 3以来 CompositeCollection 类,该类允许在其中包含多个唯一项甚至集合。WPF开发人员使用它在XAML中存储和显示不同的项。但这并不意味着它不能用于非WPF情况。

    下面是一个示例,我在其中存储从字符串到小数的不同内容,并提取和枚举所有项,然后是特定类型的项:

    CompositeCollection cc = new CompositeCollection();
    
    cc.Add(1);
    cc.Add("Item One");
    cc.Add(1.0M);
    cc.Add(1.0);
    cc.Add("Done");
    
    Console.WriteLine ("Every Item");
    
    foreach (var element in cc)
        Console.WriteLine ("\t" + element.ToString());
    
    Console.WriteLine (Environment.NewLine + "Just Strings");
    
    foreach (var str  in cc.OfType<string>())
        Console.WriteLine ("\t" + str);
    
    /* Outputs:
    
    Every Item
      1
      Item One
      1.0
      1
      Done
    
    Just Strings
      Item One
      Done
    
    */
    
        8
  •  1
  •   CodingWithSpike    15 年前

    我相信您的集合都必须是相同的MyClass类型(在T中必须是相同的),因为编译器不知道您在集合中向哪些元素添加了哪些类型。

    换句话说,如果要向列表中添加2个元素:

    list.Add(new MyClass<string>());
    list.Add(new MyClass<int>());
    

    然后尝试引用一个:

    var myItem = list[1];
    

    编译器不知道在元素处为MyClass列表分配了什么泛型 1 因为元素是在运行时添加的,而泛型是在编译时确定的。

    我很确定你想做的事是办不到的。


    如果预先知道元素的数目,也许可以使用 Tuple ?

        9
  •  1
  •   John K    15 年前

    伊利斯特

    无法定义可接受泛型类任何风格的泛型集合…工业工程 IList<MyClass> . 泛型类对于开发人员来说只是一个捷径,可以节省编写大量重复代码的时间,但是在编译时,泛型类的每一种风格都被转换为具体的类型。也就是说,如果你有 MyClass<string> , MyClass<int> , MyClass<bool> 然后编译器将生成3个独立的类。做你想做的事情的唯一方法就是为你的泛型提供一个接口。

    public interface IMyGeneric {
        Type MyType { get; set;}    
    }
    
    class MyGeneric<T> : IMyGeneric {
    
        public MyGeneric() {
            MyType = typeof(T);
        }
    
        public Type MyType {
            get; set;
        }
    }
    

    然后你可以说

    IList<IMyGeneric> list = new List<IMyGeneric>();
    list.add(new MyGeneric<string>());
    list.add(new MyGeneric<int>());
    
    推荐文章