订单只读列表

时间:2014-10-27 15:20:34

标签: c#

我有一个只读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的添加功能对其他类隐藏?

5 个答案:

答案 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#中的东西有多启发。