【问题标题】:Generic type's causing issue C#.net泛型类型导致问题 C#.net
【发布时间】:2012-09-11 12:17:27
【问题描述】:

我有一个名为 GroupItem 的类,我可以在这里存储任何类型,比如 int、string、decimal、datetime 等。然后,我有 GroupItems 可以存储任何 groupItem。我正在使用 arraylist 来存储所有 groupItem。

public class GroupItem<T>
{
    private string heading;
    private List<T> items = new List<T>();

    public GroupItem() { }

    public string Heading
    {
        get { return heading; }
        set { heading = value; }
    }

    public List<T> Items
    {
        get { return items; }
        set { items = value; }
    }

    public void Add(T value)
    {
        this.items.Add(value);
    }

    public T this[int index]
    {
        get
        {
            return this.items[index];
        }
    }
}

public class GroupItems
{
    private string groupName;
    private List<object> items = new List<object>();

    public string GroupName
    {
        get { return groupName; }
        set { groupName = value; }
    }

    public GroupItems() { }

    public void Add(object value)
    {
        this.items.Add(value);
    }

    public object this[int index]
    {
        get
        {
            return this.items[index];
        }
    }
}

我想从 GroupItems 中检索。如何在 groupItems 中获取通用项目的值?

我现在在 groupitems 中插入两个项目,datetime 和 int。现在我想检索 groupitems[2] 值,但是我如何在不知道它是什么的情况下将其转换为 groupItem。甚至我们可以通过 getType().getGenericarguments()[0] 获得它的通用参数。但是我怎样才能基于它创建一个实例。

【问题讨论】:

  • 不要使用ArrayList,它已经过时了。有List&lt;T&gt;
  • 我确信许多关于 .net 的 CS 课程仍然是在考虑 .Net 1.1 的情况下教授的。没有泛型、LINQ 或 WPF。
  • 我同意,如果您使用的是 .NET 2.0 或更高版本,则可以选择 List&lt;T&gt;,但无论如何,ArrayList 没有被标记为过时即使在 .NET 4.0 中(甚至在 .NET 4.5 的预览文档中)
  • 康拉德,我同意你的看法。即使我可以使用 List>.. 数组列表也没有问题。我想知道插入项目后,我怎样才能找回它?我可以将第一项与 int 一起使用,第二项与小数一起使用等等......我想根据插入的元素创建一个实例。
  • Raj,你说的“我怎样才能得到组项目中存储的项目”是什么意思?请解释您真正想要达到的目标以及对您造成任何问题的原因。

标签: c# generics


【解决方案1】:

如果列表存储异构项目,那么我建议您需要一个通用的非泛型接口或基类。所以,假设我们有

interface IGroupItem {
// the non-generic members, and maybe
// "object Value {get;}" etc, and maybe
// "Type ItemTypr {get;}"
}

你会得到:

class GroupItem<T> : IGroupItem {...}

然后你会使用

List<IGroupItem> ...

代替 ArrayList,或者,坦率地说,代替 GroupItems {...}

【讨论】:

  • 天哪,我刚刚尝试使用数组列表。忽略那个。将其存储在 groupItems 中后,我该如何检索?
  • @Raj 说真的,你不需要 GroupItems - 它没有添加任何内容(仅在列表中)。但如果你真的想要那个;通过返回列表的枚举器实现IEnumerable&lt;IGroupItem&gt;,和/或添加IGroupItem this[int index] 索引器
【解决方案2】:

我要做的是创建一个通用集合,例如:

public class GroupItems<T> : List<GroupItem<T>>
{
}

如果您需要扩展列表的基本功能,您还可以扩展Collection&lt;T&gt; 并覆盖您需要的方法:

public class GroupItems<T> : Collection<GroupItem<T>>
{
    protected override void InsertItem(int index, T item)
    {
         // your custom code here
         // ...

         // and the actual insertion
         base.InsertItem(index, item);
    }
}

【讨论】:

  • 在大多数情况下,直接处理 GroupItem&lt;T&gt; 的列表可能比通过 GropuItems 代理更有用。
  • 我正在使用 2.0。即使我同样加载,我该如何检索它?第一个元素可能包含 GroupItem、第二个 item int 等,我想根据我插入的内容创建一个实例。
  • @raj “第一项是字符串,第二项是 int”等就是我的意思:异构数据(与同质数据相反,同质数据是相同的类型)
  • 好的,我没听懂你的问题。在这种情况下,我会选择 Marc 的解决方案。
  • 是的,它只是异构数据,但这并不能解决我的问题。 :(
【解决方案3】:

将您的 GroupItems 类替换为 List&lt;GroupItem&lt;T&gt;&gt; 怎么样?

【讨论】:

  • 伙计们,这真的与存储无关……因为存储它有多种可能性。但是我想知道如何检索它。例如你的,我已经插入了。我想创建一个 GroupItem 的实例,它保存在第一项中。告诉我如何找回它。
【解决方案4】:

根据您对 GroupItem 所做的事情,您应该像其他人提供的那样从 List/Collection 继承,或者在您的类中使用通用集合 例如

    class GroupItem<T> 
{
    private List<T> items = new List<T>();

    public void Add(T value)
    {
        items.Add(value);


    }
    public T Get()
    {
       //replace with some logic to detemine what to get
       return items.First();

    }

}

【讨论】:

    【解决方案5】:

    您的问题可能涉及两种情况:

    1. 您只想将GroupItem 类型为T 的集合存储在GroupItems 类中。
    2. 您希望在类GroupItems 中存储任意类型的通用GroupItem 的集合。为了更清楚地说明,我的意思是您可以将 GroupItem&lt;DateTime&gt;GroupItem&lt;int&gt; 存储在同一个 GroupItems 类中。

    以下是针对这两种情况进行存储和检索的一些方法:

    同类型

    public class GroupItem<T>
    {
        // ... Code for GroupItem<T>
    }
    
    public class GroupItems<T>
    {
        private List<GroupItem<T>> mItems = new List<GroupItem<T>>();
    
        public void Add(T item)
        {
            mItems.Add(item);
        }
    
        public T GetItem(int index)
        {
            return mItems[index];
        }
    }
    

    在这里,您将构建一个同时包含GroupItem 的集合,例如GroupItem&lt;DateTime&gt; 的集合。所有项目将属于同一类型。

    通用类型

    public interface IGroupItem
    {
        // ... Common GroupItem properties and methods
    }
    
    public class GroupItem<T>
    {
        // ... Code for GroupItem<T>
    }
    
    public class GroupItems
    {
        private List<IGroupItem> mItems = new List<IGroupItem>();
    
        public void Add(IGroupItem item)
        {
            mItems.Add(item);
        }
    
        // This is a generic method to retrieve just any group item.
        public IGroupItem GetItem(int index)
        {
            return mItems[index];
        }
    
        // This is a method that will get a group item at the specified index
        // and then cast it to the specific group item type container.
        public GroupItem<T> GetItem<T>(int index)
        {
            return (GroupItem<T>)mItems[index];
        }
    }
    

    在这里,您将能够构建和维护一个集合,该集合可以包含任何GroupItem 和任何Type。因此,您可以拥有一个 GroupItems 集合,其中包含 GroupItem&lt;DateTime&gt;GroupItem&lt;int&gt; 等项。

    请注意,这些代码示例均未考虑任何错误情况。

    【讨论】:

    • 谢谢,上面的代码看起来不错。如果根据您的示例日期时间,我有两个项目,则 int。我将如何识别第二个元素 T 的类型?创建实例时?
    • 我想你会在创建实例时明确定义它,即:IGroupItem item = new GroupItem&lt;DateTime&gt;();IGroupItem item = new GroupItem&lt;int&gt;();
    【解决方案6】:

    考虑:您有一个项目集合;这些项目可以具有任何运行时类型(字符串、整数等)。因此,集合项的静态类型必须是对象。

    您似乎希望能够从具有强静态类型的列表中检索项目。如果没有大量的条件逻辑(或反射),这是不可能的。例如:

    object item = collection[0];
    if (item is int)
        //do something with an int
    else if (item is string)
        //do something with a string
    

    现在假设我们不是用collection[0] 的值“做某事”,而是将值分配给一个变量。我们可以做以下两件事之一:

    • 在这两种情况下使用相同的变量,在这种情况下静态类型必须是对象。
    • 使用单独的变量,在这种情况下静态类型将是string或int,但在条件逻辑之外,我们无法知道哪个变量保存collection[0]的值。

    这两种方法都不能真正解决问题。

    通过创建GroupItem&lt;T&gt;,您为这个问题添加了一个间接级别,但潜在的问题仍然存在。作为练习,尝试修改示例,但从“考虑:您有一个项目集合;这些项目的类型为 GroupItem&lt;T&gt;,其中 T 可以是任何运行时类型(字符串、int 等)。”

    【讨论】:

      【解决方案7】:

      感谢您的意见。

      我自己使用多种重载方法解决了这个问题。

      例如:

      private void Print(GroupItem<string> items)
      {
      ///custom coding
      }
      private void Print(GroupItem<int> items)
      {
      ///custom coding
      }
      

      虽然它的效率不够高,但我想这样做,因为它是 .net 2.0。

      我现在正在使用新算法在 .Net 4.0 中对此进行改进。

      非常感谢您的所有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 2011-01-07
        • 1970-01-01
        相关资源
        最近更新 更多