c# - 从 List<T> 高效地返回 IList<Interface>(避免从 List<T> 转换为 List<I>)

标签 c# interface casting

我有以下代码:

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> 的类充当代理人。考虑到它是只读的,它可能是“协变的”(不是语言方面的,而是逻辑上的,这意味着它可以代理 TDestTSource 的子类/接口(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/

相关文章:

java - 转换参数如何影响 java 中的覆盖和重载方法?

c# - 项目之间的交互

c# - 在 C# 中使用 LINQ 时函数求值超时

c# - 实现接口(interface)和访问方法

c++ - dynamic_cast 不保证一个有效的、完整的对象?

casting - cast(T)x 和 to!T(x) 之间的区别

c# - UI自动化和菜单项

c# - 从 MainPage.xaml.cs 文件获取字符串变量的值到 Windows Phone 中的 MainPage.xaml 文件

c# - 接口(interface)编译

json - 使用 JSON 实现 io.WriterTo