我有以下代码:
public interface ISomeObject
{
IList<ISomeObject> Objects { get; }
}
public class SomeObject : ISomeObject
{
public SomeObject()
{
Objects = new List<SomeObject>();
}
public List<SomeObject> Objects
{
get;
set;
}
IList<ISomeObject> ISomeObject.Objects
{
get
{
// What to do here?
// return Objects; // This doesn't work
return Objects.Cast<ISomeObject>().ToList(); // Works, but creates a copy each time.
}
}
SomeObject
有公共(public)属性(property)Objects
返回类类型的列表。知道该类类型的客户可以使用它来做他们想做的任何事情。客户只知道 ISomeObject
可以使用Objects
属性(property)只能得到IList<ISomeObject>
.因为不允许投List<SomeObject>
至 IList<ISomeObject>
(由于 apple and banana issue )我需要一种转换它的方法。使用 Cast.ToList() 的默认方式可行,但缺点是每次评估属性时都会创建一个新列表,这可能很昂贵。改变 ISomeObject.Objects
返回 IEnumerable<ISomeObject>
另一个缺点是客户端不能再使用索引(这在我的用例中非常相关)。当在 IEnumerable 上使用时,重复使用 Linq 的 ElementAt() 调用是昂贵的。
有没有人知道如何避免这两个问题?
(当然,到处都知道 SomeObject
不是一种选择)。
最佳答案
您可以/应该实现类似于 ReadOnlyCollection<T>
的类充当代理人。考虑到它是只读的,它可能是“协变的”(不是语言方面的,而是逻辑上的,这意味着它可以代理 TDest
是 TSource
的子类/接口(interface))然后 throw NotSupportedException()
对于所有的写方法。
像这样(代码未经测试):
public class CovariantReadOlyList<TSource, TDest> : IList<TDest>, IReadOnlyList<TDest> where TSource : class, TDest
{
private readonly IList<TSource> source;
public CovariantReadOlyList(IList<TSource> source)
{
this.source = source;
}
public TDest this[int index] { get => source[index]; set => throw new NotSupportedException(); }
public int Count => source.Count;
public bool IsReadOnly => true;
public void Add(TDest item) => throw new NotSupportedException();
public void Clear() => throw new NotSupportedException();
public bool Contains(TDest item) => IndexOf(item) != -1;
public void CopyTo(TDest[] array, int arrayIndex)
{
// Using the nuget package System.Runtime.CompilerServices.Unsafe
// source.CopyTo(Unsafe.As<TSource[]>(array), arrayIndex);
// We love to play with fire :-)
foreach (TSource ele in source)
{
array[arrayIndex] = ele;
arrayIndex++;
}
}
public IEnumerator<TDest> GetEnumerator() => ((IEnumerable<TDest>)source).GetEnumerator();
public int IndexOf(TDest item)
{
TSource item2 = item as TSource;
if (ReferenceEquals(item2, null) && !ReferenceEquals(item, null))
{
return -1;
}
return source.IndexOf(item2);
}
public void Insert(int index, TDest item)
{
throw new NotSupportedException();
}
public bool Remove(TDest item)
{
throw new NotSupportedException();
}
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
像这样使用它:
IList<string> strs = new List<string>();
IList<object> objs = new CovariantReadOlyList<string, object>(strs);
关于c# - 从 List<T> 高效地返回 IList<Interface>(避免从 List<T> 转换为 List<I>),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50526268/