加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何公开只读集合的??另一种私有集合?

发布时间:2020-12-16 01:47:35 所属栏目:百科 来源:网络整理
导读:这是我的问题:有一个类包含一些类的内部集合(或列表,或数组,或类似的东西),它必须公开一个公共的只读项集合,它们是属性(或字段)内部集合中的相关项目.例如: //Inner collection consists of items of this classclass SomeClass{ public int _age; //This
这是我的问题:有一个类包含一些类的内部集合(或列表,或数组,或类似的东西),它必须公开一个公共的只读项集合,它们是属性(或字段)内部集合中的相关项目.例如:

//Inner collection consists of items of this class
class SomeClass
{
  public int _age;

  //This property is needed for exposing
  public string Age { get { return this._age.ToString(); } }
}

//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
  private List<SomeClass> _innerList = new List<SomeClass> ();

  public ReadOnlyCollection<string> Ages 
  {
     get 
     {
       //How to implement what i need?
     }
  }
}

我知道一种简单的方法,通过使用一对内部列表来实现这一点,其中第二个保留第一个所需属性的值.像这样的东西:

//Inner collection consists of items of this class
class SomeClass
{
  public int _age;

  //This property is needed for exposing
  public string Age { get { return this._age.ToString(); } }
}

//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
  private List<SomeClass> _innerList = new List<SomeClass> ();
  private List<string> _innerAgesList = new List<string> ();

  public ReadOnlyCollection<string> Ages 
  {
     get 
     {
       return this._innerAgesList.AsreadOnly();
     }
  }
}

但我不喜欢这个开销.可能有一些方法可以通过暴露接口来做我想做的事情.请帮帮我!

自由一台!
似乎找到了最佳解决方案.由于Groo的帖子

这个问题几乎是普遍的答案.这是它(我们需要添加两个实体):

public interface IIndexable<T> : IEnumerable<T>
{
    T this[int index] { get; }
    int Count { get; }
}

class Indexer <Tsource,Ttarget> : IIndexable<Ttarget>
{
    private IList<Tsource> _source = null;
    private Func<Tsource,Ttarget> _func = null;

    public Indexer(IList<Tsource> list,Func<Tsource,Ttarget> projection)
    {
        this._source = list;
        this._func = projection;
    }

    public Ttarget this[int index] { get { return this._func(this._source[index]); } }

    public int Count { get { return _source.Count; } }

    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

    public IEnumerator<Ttarget> GetEnumerator()
    { foreach (Tsource src in this._source) yield return this._func(src); }     
}

有了它们,我们的实现看起来像这样:

//Inner collection consists of items of this class
class SomeClass
{
  public int _age;

  //This property is needed for exposing
  public string Age { get { return this._age.ToString(); } }
}

//Keeps inner collection and expose outer read-only collection
class AnotherClass
{
  private List<SomeClass> _innerList = new List<SomeClass> ();
  private Indexer<SomeClass,string> _indexer = null;

  public AnotherClass () 
  { this._indexer = new Indexer<SomeClass,string > (this._innerList,s => s.Age); }

  public IIndexable<string> Ages { get { return this._indexer; } }
}

感谢Groo和其他回答的人.希望,这有助于其他人.

解决方法

如果您认为ReadOnlyCollection是列表中的包装器(即它不会创建所有项的副本),则开销不是那么显着.

换句话说,如果你的班级看起来像这样:

class AnotherClass
{
    private ReadOnlyCollection<string> _readonlyList;
    public ReadOnlyCollection<string> ReadonlyList
    {
        get { return _readonlyList; }
    }

    private List<string> _list;
    public List<string> List
    {
        get { return _list; }
    }

    public AnotherClass()
    {
        _list = new List<string>();
        _readonlyList = new ReadOnlyCollection<string>(_list);
    }
}

然后,对List属性的任何更改都会反映在ReadOnlyList属性中:

class Program
{
    static void Main(string[] args)
    {
        AnotherClass c = new AnotherClass();

        c.List.Add("aaa");
        Console.WriteLine(c.ReadonlyList[0]); // prints "aaa"

        c.List.Add("bbb");
        Console.WriteLine(c.ReadonlyList[1]); // prints "bbb"

        Console.Read();
    }
}

您可能遇到线程安全问题,但暴露IEnumerable甚至更糟.

就个人而言,我使用自定义IIndexable< T>接口与几个方便的包装类和扩展方法,我在我的代码中使用不可变列表.它允许随机访问列表元素,并且不公开任何修改方法:

public interface IIndexable<T> : IEnumerable<T>
{
    T this[int index] { get; }
    int Length { get; }
}

它还允许类似LINT的扩展方法,如Skip,Take和类似的,由于索引功能,它们与LINQ相比具有更好的性能.

在这种情况下,您可以实现这样的投影:

public class ProjectionIndexable<Tsrc,Ttarget> : IIndexable<Ttarget>
{
    public ProjectionIndexable
         (IIndexable<Tsrc> src,Func<Tsrc,Ttarget> projection)
    {
        _src = src;
        _projection = projection;
    }

    #region IIndexable<Ttarget> Members

    public Ttarget this[int index]
    {
        get { return _projection(_src[index]); }
    }

    public int Length
    {
        get { return _src.Length; }
    }

    #endregion

    #region IEnumerable<Ttarget> Members

    // create your own enumerator here

    #endregion
}

并像这样使用它:

class AnotherClass
{
    private IIndexable<string> _readonlyList;
    public IIndexable<string> ReadonlyList
    {
        get { return _readonlyList; }
    }

    private List<SomeClass> _list;
    public List<SomeClass> List
    {
        get { return _list; }
    }

    public AnotherClass()
    {
        _list = new List<SomeClass>();
        _readonlyList = new ProjectionIndexable<SomeClass,string>
             (_list.AsIndexable(),c => c.Age);
    }
}

[编辑]

与此同时,我posted an article在CodeProject上描述了这样一个集合.我已经看到你已经自己实现了它,但你可以查看它并重用你认为合适的部分代码.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读