【问题标题】:Block the List.Add() method阻止 List.Add() 方法
【发布时间】:2016-06-09 15:40:49
【问题描述】:

我有一个包含私有列表的类。我创建了一个 getter 和一个向列表添加元素的方法:

public class Test{

    private List<T> myList;
    public List<T> MyList
    {
        get { return myList; }
    }

    public Test()
    {
         myList = new List<T>();
    }

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         myList.Add(element);
    }
}

由于每次将一个元素添加到我的列表中,我都想做更多的事情,我不希望有人在代码的某些部分直接添加一个元素:

Test test = new Test();

// Wrong
test.MyList.Add(element);

// Right
test.AddElements(element);

我曾考虑创建一个实现 IList 接口并覆盖 Add() 方法的新类,但我想知道是否有更简单/优雅的方式来“阻止”这个 Add() 方法。

【问题讨论】:

  • 如果您不希望有人能够修改它,请不要公开List。你可以暴露ReadOnlyCollection,然后没有人可以添加(除非他们使用反射)。

标签: c# .net


【解决方案1】:

如果您的 getter 的唯一原因是添加元素,您根本不需要直接访问列表,但您可以将对 Add-method 的调用包装到您自己的方法中:

class MyClass<T> {
    private List<T> _myList ...

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         _myList.Add(element);
    }
}

CA1002 进一步避免了暴露通用列表

【讨论】:

  • 不幸的是我必须从外部使用列表的元素,所以我需要访问它...
【解决方案2】:

在 Test 类中将 List 暴露为 IReadOnlyList&lt;T&gt; 然后你将不能直接使用 MyList.Add

public class Test{

    private List<T> myList;
    public IReadOnlyList<T> MyList
    {
        get { return myList; }
    }

    public Test()
    {
         myList = new List<T>();
    }

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         myList.Add(element);
    }
}

Edit 将其 IEnumerable 更新为 IReadOnlyList。使用 IReadOnlyList 有好处 - IEnumerable<T> vs IReadOnlyList<T>

【讨论】:

    【解决方案3】:

    如果您至少使用 .NET 4.5,请返回 IReadOnlyList&lt;T&gt;

    public class Test{
    
        private List<T> myList;
        public IReadOnlyList<T> MyList
        {
            get { return myList; }
        }
    
        public Test()
        {
             myList = new List<T>();
        }
    
        public void AddElements(T element)
        {
             // Do dome stuff, subscribe to an event of T
             myList.Add(element);
        }
    }
    

    【讨论】:

    • @JeroenvanLangen 当然可以,但总有办法获取数据。
    • 我认为这工作得很好而且它不会创建副本。就像你说的。 “总有办法获取数据”;-)
    • 也许是我,但 IReadOnlyList 不保护免于强制转换,看来您可以通过强制转换添加。
    【解决方案4】:

    我会以ReadOnlyCollection&lt;T&gt; 的身份返回

    像这样使用它:

    public class Test<T> 
    {
    
        private List<T> myList;
        public ReadOnlyCollection<T> MyList
        {
            get { return myList.AsReadOnly(); }
        }
    
        public Test()
        {
            myList = new List<T>();
        }
    
        public void AddElements(T element)
        {
            // Do dome stuff, subscribe to an event of T
            myList.Add(element);
        }
    }
    

    这样可以防止强制转换...它将用 ReadOnlyCollection 类包装您的 List&lt;&gt;


    或者您可以将其作为Array 返回,例如:

    public T[] MyList
    {
        get { return myList.ToArray(); }
    }
    

    ToArray() 方法将创建列表的副本


    当它作为IReadOnlyList&lt;T&gt; 返回时。你可以简单地把它扔回去..

    Test test = new Test<int>();
    
    test.AddElements(10);
    
    ((List<int>)test.MyList).Add(20);
    
    foreach(var i in test.MyList)
        Console.WriteLine(i);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 2015-01-15
      • 2013-01-14
      • 2011-08-11
      • 2016-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多