【问题标题】:Having a collection in class [duplicate]在课堂上有一个集合[重复]
【发布时间】:2014-02-10 08:00:48
【问题描述】:

当一个类必须具有某种对象的容器(集合)时,有多种选择,我想知道我更喜欢哪种实现方式。

这里遵循我找到的选项:

public class AClass : IEnumerable<string>{
   private List<string> values = new List<string>()

   IEnumerator IEnumerable.GetEnumerator()
   {
      return GetEnumerator();
   }

   public IEnumerator<T> GetEnumerator(){
      return values.GetEnumerator();
   }
}

优点:AClass 不依赖于集合的具体实现(在本例中为 List)。

缺点:AClass 没有添加和删除元素的接口

public class AClass : ICollection<string>{
   private List<string> values = new List<string>()

   IEnumerator IEnumerable.GetEnumerator()
   {
      return GetEnumerator();
   }

   public IEnumerator<T> GetEnumerator(){
      return values.GetEnumerator();
   }

   //other ICollectionMembers
}

优点:与 IEnumerable 相同,并且具有添加和删除元素的接口

缺点:ICollection 接口定义了其他很少使用的方法,仅仅为了接口而实现这些方法很无聊。 IEnumerable LINQ 扩展也负责其中的一些。

public class AClass : List<string>{

}

优点:无需实现任何方法。调用者可以调用 List 实现的任何方法

缺点:AClass 依赖于集合 List,如果它发生变化,可能需要更改一些调用者代码。 AClass 也不能继承任何其他类。

问题是:我更喜欢哪一个声明我的类包含支持添加和删除操作的集合?或者其他建议...

【问题讨论】:

    标签: c# collections


    【解决方案1】:

    我的建议是在你的类中定义一个通用 List 并编写额外的 AddRemove 这样的方法并实现 IEnumerable:

    public class MyClass : IEnumerable
    {
        private List<string> myList;
    
        public MyClass()
        {
            myList = new List<string>();
        }
    
        public void Add(string item)
        {
            if (item != null) myList.Add(item);
        }
    
        public void Remove(string item)
        {
            if (myList.IndexOf(item) > 0) myList.Remove(item);
        }
    
        public IEnumerable<string> MyList { get { return myList; } }
    
        public IEnumerator GetEnumerator()
        {
            return myList.GetEnumerator();
        }
    }
    

    如果您不想实现自己的集合,这是最好的方法。您不需要实现AddRemove 方法的接口。我猜像这样的其他方法符合您的需求。

    【讨论】:

    • 不需要添加和删除方法,因为您已经有一个属性来获取列表。我喜欢这个想法,但我会让它返回 ICollection,这样它就不会像我的第三个选项那样有同样的缺点。
    • 你对,你可以把它改成ICollection,或者IEnumerable更好。如果你返回IEnumerable,用户不能直接将项目添加到列表中。
    【解决方案2】:

    这确实是一个基于意见的问题,并不是 SO 的具体用途。但是,正如您所列出的,所有实现都有不同的优缺点,实际上,您实现的是最适合应用程序使用的选项。

    在我的个人意见中,我会选择选项一并添加与内部集合交互所需的方法。这实现起来非常简单,使用起来也很简单。

    类似的东西。

    public class AClass : IEnumerable<string>
    {
        public AClass()
        {
            this.values = new List<string>();
        }
    
        private readonly List<string> values;
    
        public void Add(string inputString)
        {
            this.values.Add(inputString);
        }
    
        public void Remove(string inputString)
        {
            this.values.Remove(inputString);
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public IEnumerator<string> GetEnumerator()
        {
            return values.GetEnumerator();
        }
    }
    

    现在它具有简单的添加\删除功能。另请注意,我使用了 readonly 列表,因为在调用构造函数后您的列表不需要休息。

    按评论更新。

    是的,您确实已经从 List 转换为 AClass 其他类(无论如何您都必须这样做)。我添加了一个额外的构造函数和一个隐式运算符,以从构造函数中的 List 或 IEnumerable 进行强制转换。

    public class AClass : IEnumerable<string>
    {
        public static implicit operator AClass(List<string> collection)
        {
            return new AClass(collection);
        }
    
        public static implicit operator List<string>(AClass aClass)
        {
            return aClass.values;
        }
    
        public AClass()
        {
            this.values = new List<string>();
        }
    
        public AClass(IEnumerable<string> collection)
        {
            this.values = collection.ToList();
        }
    
        private readonly List<string> values;
    
        public void Add(string inputString)
        {
            this.values.Add(inputString);
        }
    
        public void Remove(string inputString)
        {
            this.values.Remove(inputString);
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public IEnumerator<string> GetEnumerator()
        {
            return values.GetEnumerator();
        }
    }
    

    这可以用作以下方式。:

    List<string> listA = new List<string>();
    
    AClass classA = new AClass(); //parameterless constructor
    AClass classA1 = new AClass(listA); //simple constructor call with collection
    AClass classA2 = (AClass)listA; //direct cast
    List<string> listB = (List<string>)listA; //cast back to a list
    

    只是一个想法,仍然是 个人意见

    【讨论】:

    • 这样做的缺点是您必须强制转换为 AClass 才能添加和删除(如果您只知道它是一个 IEnumerable)
    • 我已经根据评论更新了回复
    • 我不太喜欢铸造运算符的 Ideia(可能是个人喜好),但有构造函数是一个很好的选择。
    • 我更喜欢按照 Selman 的建议将集合公开为属性,因此我不必实现添加或删除方法。
    • 很公平......很高兴你找到了答案......
    【解决方案3】:

    我喜欢你解释想法的方式。

    您找到了 3 种解决某些问题的完美方法。你的优点和缺点让我觉得你理解正确。

    没有解决所有问题的灵丹妙药。但您最好拥有一个软件架构师工具箱,其中包含设计模式和一些常识。

    下次遇到挑战时,请使用最适合工作的工具!

    【讨论】:

    • 我猜,在完成计算机工程大学学位后几乎有这样的疑问是相当糟糕的。但是,嘿,应该提出所有问题,我也在寻找一致性,因为每当这个问题发生时,我认为我以不同的方式面对它。现在我可以保持一致性和我喜欢并觉得合理的方式来实施它。
    • 这根本不是蝙蝠,恰恰相反。当我想在其构造函数中填充一些已知数据时,我通常使用泛型 List 或从它继承。但并不总是这样。
    【解决方案4】:

    这只是对 Selman 建议的一小部分改编,因此他的回答符合我的期望:

    public class MyClass : IEnumerable<string>
    {
       private List<string> myList;
    
       public MyClass()
       {
           myList = new List<string>();
       }
    
       public ICollection<string> MyList { get { return myList; } }
    
       IEnumerator IEnumerable.GetEnumerator()
       {
          return GetEnumerator();
       }
    
       public IEnumerator<T> GetEnumerator(){
          return myList.GetEnumerator();
       }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-09
      • 2016-08-02
      • 2021-09-21
      • 2010-12-31
      • 2013-08-02
      • 1970-01-01
      • 2012-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多