从System.Collections.Generic.IList<object>转换为System.Collections.IList

huangapple go评论79阅读模式
英文:

Convert from System.Collections.Generic.IList<object> to System.Collections.IList

问题

我已经实现了以下类:

class LazyList&lt;T&gt; : IList&lt;T&gt;
{
    public LazyList(IEnumerable&lt;T&gt; enumerable) { }
}

我需要将这个类与非泛型的旧版 System.Collections 一起使用。我已经通过使用 IEnumerable.Cast&lt;object&gt;() 解决了一半的问题,如此处描述:https://stackoverflow.com/a/776407/2109230/

然而,我需要将 LazyList&lt;T&gt; 强制转换为非泛型的 IList 以完成重构过程。我应该如何实现这个?

更新 1:

LazyList 基本上帮助我重构一个在迭代 IDataReader 后返回 IList 的方法。我使用从这个方法返回的数据来通过 WebSocket 发送一些更新。重点是不断地发送数据,而不是在处理整个 IDataReader 后才发送。我已经使用 yield return 返回了一个懒惰的 IEnumerable,但其他方法要求重构后的方法返回 IList。因此,我想到了 LazyList 的主意。

实际上有两种方法,一种返回 IList&lt;T&gt;,我已经成功地重构了它,另一种返回 IList。我想知道是否有一种更简单的方法来重构返回 IList 的版本,而不必实现非泛型的 LazyList。但是,我已经这样做了,而且情况并不那么糟糕。

英文:

I have implemented the following class:

class LazyList&lt;T&gt; : IList&lt;T&gt;
{
    public LazyList(IEnumerable&lt;T&gt; enumerable) { }
}

I need to use this class with non-generic legacy System.Collections. I have solved half of the problem by using IEnumerable.Cast&lt;object&gt;() as described here <https://stackoverflow.com/a/776407/2109230/>.

However, I need to cast LazyList&lt;T&gt; to non-generic IList to complete the refactor process. How can I achieve this?

UPDATE 1:

LazyList basically helps me refactor a method that returns IList after iterating an IDataReader. I use data returned from this method to send some updates over WebSocket. The point is to send data constantly, not after processing the entire IDataReader. I have used yield return to return a lazy IEnumerable, but other methods require the refactored method to return IList. So, I came up with the idea of LazyList.

There are actually two methods, one returning IList&lt;T&gt;, which I have refactored successfully, and another returning IList. I wanted to see if there is a simpler way to refactor the version returning IList, without implementing non-generic LazyList. However, I did that and it wasn't that bad.

答案1

得分: 1

你应该按照List&lt;T&gt;所做的方式进行操作 - 实现两个接口并使用显式接口实现来消除一些重复(请参阅源代码)并限制暴露的合同。以下是一个起始示例:

class LazyList&lt;T&gt; : IList&lt;T&gt;, IList
{
    public LazyList(IEnumerable&lt;T&gt; enumerable) { }
  
    public void Add(T item) =&gt; throw new NotImplementedException();
    public int Count { get; }

    public int Add(object? item)
    {
        Add((T)item!); // 调用泛型实现
        return Count - 1;
    }

    int IList.IndexOf(object? item)
    {
        if (IsCompatibleObject(item))
        {
            return IndexOf((T)item!); // 调用泛型实现
        }
        return -1;
    }

    public int IndexOf(T item) =&gt; throw a NotImplementedException();
    
    private static bool IsCompatibleObject(object? value) =&gt; (value is T) || (value == null &amp;&amp; default(T) == null);

   // ...
}
英文:

You should follow the pattern the List&lt;T&gt; does - implement both interfaces and use explicit interface implementations to remove some duplication (see the source code) and limit the exposed contract. Something to get you started:

class LazyList&lt;T&gt; : IList&lt;T&gt;, IList
{
    public LazyList(IEnumerable&lt;T&gt; enumerable) { }
  
    public void Add(T item) =&gt; throw new NotImplementedException();
    public int Count { get; }

    public int Add(object? item)
    {
        Add((T)item!); // call to the generic implementation
        return Count - 1;
    }

    int IList.IndexOf(object? item)
    {
        if (IsCompatibleObject(item))
        {
            return IndexOf((T)item!); // call to generic 
        }
        return -1;
    }

    public int IndexOf(T item) =&gt; throw new NotImplementedException();
    
    private static bool IsCompatibleObject(object? value) =&gt; (value is T) || (value == null &amp;&amp; default(T) == null);

   // ...
}

答案2

得分: 1

我同意 @Panagiotis Kanavos 的说法:“IList 不是 IList&lt;object&gt;,它是一个完全不同的接口”。此外,如果使用非泛型 IEnumerable 创建的 LazyList&lt;T&gt;[index] 访问,如果 T 被初始化为除 object 以外的任何类型,将会引发转换错误。

最后,我另外创建了一个实现了 IList 接口的类,使用原始的 LazyList&lt;T&gt;,以避免将 object 强制转换为 T:

public class LazyList : IList
{
	LazyList&lt;object&gt; _lazyList;

	public LazyList(IEnumerable enumerable)
	{
		_lazyList = new LazyList&lt;object&gt;(enumerable.Cast&lt;object&gt;());
	}
}

虽然我复制了方法,但似乎没有其他方法。

英文:

I agree with @Panagiotis Kanavos stating that: "An IList isn't an IList&lt;object&gt;, it's a completely different interface". In addition, accessing LazyList&lt;T&gt;[index] created from a non-generic IEnumerable, will throw a conversion error if T is initialized with anything else than object.

I ended up with another class implementing IList using the original LazyList&lt;T&gt;, to avoid casting object to T:

public class LazyList : IList
{
	LazyList&lt;object&gt; _lazyList;

	public LazyList(IEnumerable enumerable)
	{
		_lazyList = new LazyList&lt;object&gt;(enumerable.Cast&lt;object&gt;());
	}
}

I did duplicate the methods, but it seems there is no other way.

huangapple
  • 本文由 发表于 2023年7月11日 01:37:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76656094.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定