比如,我们有一个带有私有List的泛型类.我们可以使它至少以两种方式返回此列表的只读包装:
public class Test<T>
{
public List<T> list = new List<T>();
public IEnumerable<T> Values1
{
get
{
foreach (T i in list)
yield return i;
}
}
public IEnumerable<T> Values2
{
get
{
return list.AsReadOnly();
}
}
}
Run Code Online (Sandbox Code Playgroud)
双方Values1并Values2反映底层集合中的任何chages并防止它通过自己修改.
哪种方式更好?应该注意什么?或者还有其他更好的方法吗?
我的问题与这个关于使用IEnumerable<T>vs的问题有关IReadOnlyCollection<T>.
我也经常习惯IEnumerable<T>将集合作为返回类型和参数公开,因为它既可以是不可变的,也可以是懒惰的.
但是,我越来越关注代码中地点的扩散,我必须枚举一个参数以避免ReSharper给出的可能的多个枚举警告.我理解为什么ReSharper建议这一点,我同意它建议的代码(下面)以确保封装(即,没有关于调用者的假设).
Foo[] arr = col as Foo[] ?? col.ToArray();
Run Code Online (Sandbox Code Playgroud)
但是,我发现此代码的重复性是污染性的,我同意一些IReadOnlyCollection<T>更好的替代方案,特别是本文中提出的观点,其中指出:
最近,我一直在考虑回归的优点和缺点
IEnumerable<T>.从积极的一面,它大约是最小的一个接口获得,所以给人们留下你的方法作者比承诺更重的替代需要更多的灵活性
IList<T>或(但愿)阵列.但是,正如我在上一篇文章中所概述的那样,
IEnumerable<T>回归诱使来电者违反Liskov替代原则.这太容易让他们使用LINQ扩展方法,如Last()和Count(),其语义IEnumerable<T>不答应.我们需要的是一种更好的方法来锁定一个返回的集合,而不会让这种诱惑如此突出.(我想起Barney Fife艰难地学习这一课.)
IReadOnlyCollection<T>在.NET 4.5中输入new.它只添加一个属性IEnumerable<T>:Count属性.通过承诺计数,你向你的来电者保证你IEnumerable<T>确实有一个终点.然后,他们可以使用LINQ扩展方法,如Last()清醒的良心.
但是,正如观察者可能已经注意到的那样,本文仅讨论使用IReadOnlyCollection<T>返回类型.我的问题是,相同的论点同样适用于将其用于参数吗?对此的任何理论思考或评论也将受到赞赏.
事实上,我认为使用的一般经验法则IReadOnlyCollection<T>是,如果使用的话,可能存在多次枚举(相对于ReSharper警告)IEnumerable<T>.否则,请使用IEnumerable<T>.
我正在尝试ReadOnlyCollection使用protobuf-net 序列化和反序列化.但是,当protobuf-net尝试将List转换为ReadOnlyCollection时,反序列化时会抛出异常.
var roc = new ReadOnlyCollection<byte>(new byte[] {1, 2, 3});
var ms = new MemoryStream();
Serializer.Serialize(ms, roc);
ms.Position = 0;
var roc2 = Serializer.Deserialize<ReadOnlyCollection<byte>>(ms);
Console.WriteLine( BitConverter.ToString( roc2.ToArray() ) );
Run Code Online (Sandbox Code Playgroud)
有没有办法把它作为一个ReadOnlyCollection而不是序列化/反序列化List?在实际的应用程序中,它ReadOnlyCollection是我想要序列化的不可变对象的一部分,并且宁愿将它保留为ReadOnlyCollection.
此代码工作的原因是由于Enumerator无法修改集合的事实:
var roList = new List<string>() { "One", "Two", "Three" };
IEnumerable<object> objEnum = roList;
Run Code Online (Sandbox Code Playgroud)
如果我们尝试用a做同样的事情List<object>,而不是IEnumerable<object>,我们会得到一个编译器错误告诉我们我们不能隐式地将类型转换List<string>为List<object>.好吧,那个是有道理的,在我看来,这是微软的一个很好的决定,作为从数组中吸取的教训.
但是,我无法弄清楚为什么世界上这条强硬的规则适用于类似的东西ReadOnlyCollection?我们将无法修改其中的元素ReadOnlyCollection,因此导致Microsoft阻止我们使用只读内容的协方差的安全问题是什么?是否有可能修改Microsoft试图考虑的集合类型,例如通过指针?
来自msdn:
表示键/值对的通用只读集合.
但请考虑以下事项
class Test
{
public IReadOnlyDictionary<string, string> Dictionary { get; } = new Dictionary<string, string>
{
{ "1", "111" },
{ "2", "222" },
{ "3", "333" },
};
public IReadOnlyList<string> List { get; } =
(new List<string> { "1", "2", "3" }).AsReadOnly();
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
var dictionary = (Dictionary<string, string>)test.Dictionary; // possible
dictionary.Add("4", "444"); // possible
dictionary.Remove("3"); // possible
var list = (List<string>)test.List; // …Run Code Online (Sandbox Code Playgroud) ReadOnlyCollection<T>实现ICollection<T>具有添加和删除等方法的界面.我知道如何使用属性从Intellisense隐藏方法,但是如果我尝试使用这些方法,怎么可能导致实际的编译错误?
(顺便说一句,我知道在ROC上调用Add和Remove是没有意义的,这是一个关于导致继承的memebers的编译错误的问题,而不是使用正确的数据结构).
今天我碰到一个两难之间有什么区别来ReadOnlyCollection<T>,并ReadOnlyCollectionBuilder<T>在.net中?
在ReadOnlyCollection<T>对象中,我们无法添加和删除项目.
在ReadOnlyCollectionBuilder<T>对象中我们可以添加和删除项目.
如果我们可以添加和删除ReadOnlyCollectionBuilder<T>对象中的项目,那么为什么名称只读?
public class RegistrationManager
{
public List<object> RegisteredObjects;
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
我希望RegisterObjects可以从课堂外访问,但是填充RegisterObjects列表的唯一方法是通过TryRegisterObject(object o).
这可能吗 ?
根据FxCop的建议和我个人的倾向,我一直鼓励我正在指导的团队尽可能多地使用ReadOnlyCollections.仅限于列表的收件人无法修改其内容.在他们的理论中,这是面包和黄油.问题是List <>接口更丰富,暴露了各种有用的方法.他们为什么做出这个选择?
你只是放弃并返回可写的集合吗?您是否返回只读集合,然后将它们包装在可写的多样性中?AHHHHH.
更新:谢谢我熟悉框架设计指南,这就是为什么团队使用FxCop来强制执行它.然而,这个团队和VS 2005一起生活(我知道,我知道)并告诉他们LINQ/Extension方法可以解决他们的问题只会让他们感到难过.
他们已经了解到List.FindAll()和.FindFirst()比编写foreach循环更清晰.现在我正在推动他们使用ReadOnlyCollections,他们失去了清晰度.
也许有一个更深层次的设计问题,我没有发现.
- 抱歉,原帖应该提到了VS2005的限制.我和我共处了很长时间以至于我没有注意到.
这是示例代码:
static class Store
{
private static List<String> strList = new List<string>();
private static HashSet<String> strHashSet = new HashSet<string>();
public static List<String> NormalList
{
get { return strList; }
}
public static HashSet<String> NormalHashSet
{
get { return strHashSet; }
}
public static IReadOnlyList<String> ReadonlyList
{
get { return (IReadOnlyList<String>)strList; }
}
public static IReadOnlyCollection<String> ReadonlyHashSet
{
get { return (IReadOnlyCollection<String>)strHashSet; }
}
public static IReadOnlyList<String> Real_ReadonlyList
{
get { return (IReadOnlyList<String>)strList.AsReadOnly(); }
}
public static IReadOnlyCollection<String> Real_ReadonlyHashSet
{
get …Run Code Online (Sandbox Code Playgroud) c# ×10
ienumerable ×2
list ×2
.net ×1
.net-4.5 ×1
collections ×1
covariance ×1
dictionary ×1
generics ×1
hashset ×1
interface ×1
protobuf-net ×1
resharper ×1