这是我的问题:有一个类包含一些类的内部集合(或列表,或数组,或类似的东西),它必须公开一个公共的只读项集合,它们是属性(或者字段)内部集合中的相关项目。例如:
//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和其他人回答。希望,这有助于其他人。
答案 0 :(得分:4)
如果您认为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; }
}
它还允许类似LIN {的类似扩展方法,如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上描述了这样一个集合。我已经看到你已经自己实现了它,但你可以查看它并重用你认为合适的部分代码。
答案 1 :(得分:2)
为什么不直接返回IEnumerable?
如果您可以访问LINQ(.NET 3.5),那么只需使用select()
public IEnumerable<string> Ages{
get{
return _innerList.Select(s => s.stringProperty);
}
}
答案 2 :(得分:1)
在这种情况下,我通常只使用IEnumerable - 如果该集合是只读的,而您不需要索引功能,则可以执行以下操作:
public IEnumerable<string> Ages
{
get
{
return this._innerList.Select(someObj => someObj.Age).ToArray();
}
}