我知道我不应该暴露一个List<T>属性,但我想知道这样做的正确方法是什么?例如,这样做:
public static class Class1
{
private readonly static List<string> _list;
public static IEnumerable<string> List
{
get
{
return _list;
//return _list.AsEnumerable<string>(); behaves the same
}
}
static Class1()
{
_list = new List<string>();
_list.Add("One");
_list.Add("Two");
_list.Add("Three");
}
}
Run Code Online (Sandbox Code Playgroud)
允许我的来电者简单地回到List<T>:
private void button1_Click(object sender, EventArgs e)
{
var test = Class1.List as List<string>;
test.Add("Four"); // This really modifies Class1._list, which is bad™
}
Run Code Online (Sandbox Code Playgroud)
所以,如果我想要一个真正不可变的List<T>,我总是要创建一个新的列表?例如,这似乎有效(测试在转换后为null):
public static IEnumerable<string> List
{
get
{
return new ReadOnlyCollection<string>(_list);
}
}
Run Code Online (Sandbox Code Playgroud)
但是我担心是否存在性能开销,因为每次有人试图访问它时我的列表都被克隆了?
揭露List<T>作为财产实际上并不是万恶之源; 特别是如果它允许预期的使用,如foo.Items.Add(...).
您可以编写一个安全的替代品AsEnumerable():
public static IEnumerable<T> AsSafeEnumerable<T>(this IEnumerable<T> data) {
foreach(T item in data) yield return item;
}
Run Code Online (Sandbox Code Playgroud)
但目前你最大的问题是线程安全.作为一个静态成员,你可能在这里遇到很大的问题,特别是如果它是像ASP.NET这样的东西.即使ReadOnlyCollection在现有列表中,也会受此影响:
List<int> ints = new List<int> { 1, 2, 3 };
var ro = ints.AsReadOnly();
Console.WriteLine(ro.Count); // 3
ints.Add(4);
Console.WriteLine(ro.Count); // 4
Run Code Online (Sandbox Code Playgroud)
因此,简单地用包装纸AsReadOnly是不是足以让你的对象是线程安全的; 它只是防止消费者添加数据(但是当你的其他线程添加数据时,他们仍然可以枚举它,除非你同步或复制).
| 归档时间: |
|
| 查看次数: |
2599 次 |
| 最近记录: |