我想弄明白,将对象的只读列表发布为公共(public)方法的最佳方式是什么?
来自 Eric Lippert's Blog ,数组有点糟糕,因为有人可以轻松添加新条目。因此,每次调用该方法时都必须传递一个新数组。
他建议,通过 IEnumerable<T>
,因为这是只读定义(没有添加、删除方法),我已经练习了很长时间。
但在我们的新项目中,人们甚至开始创建这些 IEnumerables
的数组,因为他们不知道背后的数据源,所以他们得到一个:Handling warning for possible multiple enumeration of IEnumerable
我对一种技术方法很感兴趣,即如何解决这个难题。到目前为止我想出的唯一解决方案是使用 IReadOnlyCollection
, 但这比 IEnumerable
更明确.
发布此类列表的最佳做法是什么,这些列表不应更改,但应声明为内存中列表?
最佳答案
通常 - 并且有一段时间 - 使用 immutable collections 解决了这个问题.
例如,您的公共(public)属性应该属于 IImmutableList<T>
类型, IImmutableHashSet<T>
等等。
任何IEnumerable<T>
可以转换为不可变集合:
-
someEnumerable.ToImmutableList();
-
someEnumerable.ToImmutableHashSet();
- ... 等等。
通过这种方式,您可以使用可变集合处理私有(private)属性,并仅提供不可变集合的公共(public)表面。
例如:
public class A
{
private List<string> StringListInternal { get; set; } = new List<string>();
public IImmutableList<string> StringList => StringListInternal.ToImmutableList();
}
还有一种使用接口(interface)的替代方法:
public interface IReadOnlyA
{
IImmutableList<string> StringList { get; }
}
public class A : IReadOnlyA
{
public List<string> StringList { get; set; } = new List<string>();
IImmutableList<string> IReadOnlyA.StringList => StringList.ToImmutableList();
}
检查 IReadOnlyA
has been explicitly-implemented ,因此既可变又不可变StringList
属性可以作为同一类的一部分共存。
当你想公开一个不可变的 A
时, 然后你返回你的 A
对象向上转换为 IReadOnlyA
上层将无法改变整个 StringList
在上面的示例中:
public IReadOnlyA DoStuff()
{
return new A();
}
IReadOnlyA a = DoStuff();
// OK! IReadOnly.StringList is IImmutableList<string>
IImmutableList<string> stringList = a.StringList;
避免每次都将可变列表转换为不可变列表
这应该是一种可能的解决方案,以避免每次访问不可变列表时都将源列表转换为不可变列表。
平等成员
如果项目类型覆盖 Object.Equals
和 GetHashCode
,并可选择实现 IEquatable<T>
,那么公共(public)不可变列表属性访问可能如下所示:
public class A : IReadOnlyA
{
private IImmutableList<string> _immutableStringList;
public List<string> StringList { get; set; } = new List<string>();
IImmutableList<string> IReadOnlyA.StringList
{
get
{
// An intersection will verify that the entire immutable list
// contains the exact same elements and count of mutable list
if(_immutableStringList.Intersect(StringList).Count == StringList.Count)
return _immutableStringList;
else
{
// the intersection demonstrated that mutable and
// immutable list have different counts, thus, a new
// immutable list must be created again
_immutableStringList = StringList.ToImmutableList();
return _immutableStringList;
}
}
}
}
关于c# - IEnumerable<T> 与数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33859562/