我有一个只读List,所以我可以从其他类中隐藏Add方法,如下所示:
class Foo
{
private readonly List<Bar> _Bars = new List<Bar>;
public()
{
this.Bars = _Bars.AsReadOnly();
}
public ReadOnlyCollection<Bar> Bars
{
get;
private set;
}
public void AddBar(Vector Dimensions)
{
_Bars.Add(new Bar(Dimensions));
}
}
问题是,现在我想订购Foo实例的_Bars字段,如下所示:
public void OrderBarsByVolume()
{
_Bars.OrderByDescending(o => o.Volume); //Doesn't do anything
_Bars = _Bars.OrderByDescending(o => o.Volume).ToList(); //Error: A readonly field cannot be assigned to
}
是否可以使用orderby并保持List的添加功能对其他类隐藏?
答案 0 :(得分:5)
然而,如果你稍微调整一下,那么你可以使用当前的实现。 &#34; 隐藏&#34;的想法基础数据意味着您不必在内部将其作为只读保留,而是将其公开为只读
private List<Bar> _Bars = new List<Bar>();
public ReadOnlyCollection<Bar> Bars
{
get { return _Bars.AsReadOnly(); }
}
public void OrderBy(Func<Bar, bool> src)
{
_Bars = _Bars.OrderByDescending(src);
}
...
var foo = new Foo();
foo.OrderBy(x => x.Volume);
如果您觉得每次创建新的ReadOnlyCollection
过于昂贵,请保持代码不变,只需删除readonly
修饰符
private List<Bar> _Bars = new List<Bar>;
public void OrderBy(Func<Bar, bool> src)
{
_Bars = _Bars.OrderByDescending(src).ToList();
}
答案 1 :(得分:4)
使用List<T>.Sort
方法
_Bars.Sort((x,y) => x.Volume.CompareTo(y.Volume));
答案 2 :(得分:1)
添加一个将在Foo对象中进行排序的公共方法。
答案 3 :(得分:0)
让呼叫者处理排序列表:
public IEnumerable<Bars> OrderedBars(Func<Bar, bool> sortMethod)
{
return _Bars.OrderBy(sortMethod);
}
如果你真的想要自己保留排序的条形图,你可以创建一个不可变的类,其中排序条形创建一个新的Foo
实例,然后将替换当前的实例或被调用者使用,类似的东西:
public Foo OrderBarsByVolume()
{
return new Foo() {_Bars = this._Bars.OrderByDescending(o => o.Volume)}
}
答案 4 :(得分:0)
即使詹姆斯给了你一些好的提示,仍有一些悬而未决的问题。
让我们从您的实施开始:
private readonly List<Bar> _Bars = new List<Bar>;
这不会使列表本身成为只读。仍然可以添加,删除项目或清除整个列表。关键字readonly
仅确保您无法用完全不同的列表替换整个列表。
所以你喜欢的是,在你的班级中你可以完全访问列表(所以Foo
可以添加,删除,排序项目),但是任何请求列表的人都只能阅读这个列表。这里的开放性问题是,如果有人请求列表并且之后列表从Foo更改,应该会发生什么。已经过时的清单是否应该反映这些变化?大多数情况下,你喜欢这种行为,但这实际上取决于你想要达到的目标。
这是我的代码示例,可以解决您的大部分问题:
internal class Foo
{
// The list which can be manipulated only be Foo itself.
private List<Bar> _Bars;
// The proxy that will be given out to the consumers.
private ReadOnlyCollection<Bar> _BarsReadOnly;
public Foo()
{
// Create the mutable list.
_Bars = new List<Bar>();
// This is a wrapper class that holds a
// reference to the mutable class, but
// throws an exception to all change methods.
_BarsReadOnly = _Bars.AsReadOnly();
}
public IReadOnlyList<Bar> Bars
{
// Simply give out the wrapper.
get { return _BarsReadOnly; }
}
public void AddBar(Vector dimensions)
{
// Manipulate the only intern available
// changeable list...
_Bars.Add(new Bar(dimensions));
}
public void SortBars()
{
// To change the order of the list itself
// call the Sort() method of list with
// a comparer that is able to sort the list
// as you like.
_Bars.Sort(BarComparer.Default);
// The method OrderBy() won't have any
// immediate effect.
var orderedList = _Bars.OrderBy(i => i.Volume);
// That's because it will just create an enumerable
// which will iterate over your given list in
// the desired order, but it won't change the
// list itself and so also not the outgiven wrappers!
}
}
要使用列表类的Sort()
方法,您需要一个比较器,但这很容易实现:
internal class BarComparer : IComparer<Bar>
{
public static BarComparer Default = new BarComparer();
public int Compare(Bar x, Bar y)
{
if (ReferenceEquals(x, y))
return 0;
if (ReferenceEquals(x, null))
return -1;
if (ReferenceEquals(y, null))
return 1;
return x.Volume.CompareTo(y.Volume);
}
}
我希望这能让你对C#中的东西有多启发。