有效地返回IList< Interface>来自List< T> (避免从List< T>转换为List< I>) [英] Efficiently return IList<Interface> from List<T> (avoid casting from List<T> to List<I>)

查看:56
本文介绍了有效地返回IList< Interface>来自List< T> (避免从List< T>转换为List< I>)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

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 具有一个公共属性 Objects ,该属性返回类类型的列表。知道该类类型的客户可以使用该类做他们想要的任何事情。仅了解 ISomeObject 的客户只能使用 Objects 属性来获取 IList< ISomeObject>。 。因为不允许将 List< SomeObject> 强制转换为 IList< ISomeObject> (由于苹果和香蕉问题),我需要一种转换方法。使用Cast.ToList()的默认方式有效,但缺点是每次评估属性时都会创建一个新的List,这可能会很昂贵。更改 ISomeObject.Objects 以返回 IEnumerable< ISomeObject> 还有另一个缺点,即客户端不能使用索引更多(在我的用例中这是非常相关的)。当用于IEnumerable上时,重复使用Linq的ElementAt()调用很昂贵。

SomeObject has a public property Objects that returns a List of class type. Clients knowing that class type can use that to do whatever they want. Clients only knowing about ISomeObject can use the Objects property only to get an IList<ISomeObject>. Because it is not allowed to cast List<SomeObject> to IList<ISomeObject> (due to the apple and banana issue) I need a way of converting that. The default way, using a Cast.ToList() works, but has the downside that it creates a new List each time the property is evaluated, which may be expensive. Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case). And using Linq's ElementAt() call repeatedly is expensive, when used on an IEnumerable.

有人知道如何避免出现任何一个问题吗?
(当然,让 SomeObject 到处都是已知的不是一种选择)。

Has anybody got an idea on how to avoid either problem? (of course, making SomeObject known everywhere is not an option).

推荐答案

您可以/应该实现类似于 ReadOnlyCollection< T> 充当代理。考虑到它将是只读的,因此它可以是协变的(不是语言方面的,而是逻辑上的意思,这意味着它可以代理 TDest ),它是的子类/接口。 TSource ),然后抛出NotSupportedException()用于所有写入方法。

You could/should implement a class similar to ReadOnlyCollection<T> to act as a proxy. Considering that it would be read only, it could be "covariant" (not language-side, but logically, meaning that it could proxy a TDest that is a subclass/interface of TSource) and then throw NotSupportedException() for all the write methods.

类似这样的东西(未经测试的代码):

Something like this (code untested):

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);

这篇关于有效地返回IList&lt; Interface&gt;来自List&lt; T&gt; (避免从List&lt; T&gt;转换为List&lt; I&gt;)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆