【问题标题】:Convert from IList<T> to non-generic IList从 IList<T> 转换为非泛型 IList
【发布时间】:2012-09-19 13:36:26
【问题描述】:

我正在实现IListSource,它需要一个具有以下签名的方法GetList():

IList GetList()

我正在使用 .NET 框架 2,我想返回一个实现 IList 的对象,如下所示:

public System.Collections.IList GetList()
{
    return this._mydata; // Implements IList<MyDataRow>            
}

但我得到一个编译错误:Cannot implicitly convert type MyData to System.Collections.IList。

如果我创建一个List&lt;MyDataRow&gt; 类型的new 列表,填充它并返回这个列表对象,那么它就可以工作了。换句话说,这行得通:

public System.Collections.IList GetList()
{
   List<MyDataRow> list = new List<MyDataRow>();
   foreach (MyDataRow row in this._mydata)
   {
       list.Add(row);
   }
   return list;
}

但是,为了将其从类型IList&lt;T&gt; 获取到IList,必须重新创建列表似乎非常低效。为什么我可以返回List&lt;MyDataRow&gt;' from 'GetList(),但不能返回IList&lt;MyDataRow&gt;?有谁知道我在不重新填充新列表的情况下返回IList&lt;MyDataRow&gt; 的方法?

更新:

声明了_mydata成员变量:

private MyData _mydata;

并声明了MyData:

public class MyData : IList<MyDataRow>
{
   ....
}

【问题讨论】:

  • _mydata字段声明的类型是什么?
  • @NicoleCalinoiu:根据他得到的错误信息,是MyData。

标签: c# .net list generics c#-2.0


【解决方案1】:

为什么我可以从GetList()返回List&lt;MyDataRow&gt;,但不能返回IList&lt;MyDataRow&gt;

这是因为List&lt;T&gt; 实现了IList,IList&lt;T&gt; 不能转换为IList,它们是两个独立的接口。所以回答你的问题:

有没有人知道我可以在不重新填充新列表的情况下返回IList&lt;MyDataRow&gt; 的方法?

如果具体类型实现了IList(List&lt;T&gt; 实现了),那么您可以显式地转换它,例如

return (IList)this.mydata;

更新

根据您的更新,您必须更新MyData 以实现IList,否则您别无选择,只能返回一个确实实现它的新集合。

或者,如果MyData 确实是一个通用列表,那么我建议您从List&lt;T&gt; 继承它,这样您就可以获得更多的灵活性和兼容性,例如

class MyData : List<MyDataRow>
{
}

【讨论】:

  • 这确实解释了问题,但没有提供解决方案:myData 是 IList 类型,他仍然需要调用 .ToList() 并且他想避免这种情况。跨度>
  • @Baboon 如果myData 的类型是IList&lt;MyDataRow&gt;,但具体类型是List&lt;T&gt;,那么只需要显式转换。
  • 感谢詹姆斯,您的详细回答。我要给你荣誉,因为从 List 继承的建议,而不是像我一样在我的类中封装 List 成员,确实是解决我的问题的最简单的方法。感谢您的帮助。
【解决方案2】:

MyData 类需要实现IList 以及通用版本IList&lt;T&gt;。

class MyData : IList<MyDataRow>, IList
{
}

【讨论】:

  • +1。我冒昧地修改了班级名称。 (根据OP的错误信息,类本身是MyData,而不是MyDataRow)。
【解决方案3】:

IList&lt;T&gt; 不扩展IList,因为期望通用版本的每个实现都提供与非通用版本相同的合同是不合理的。如果它确实扩展了IList,那么有人可以获取从GetList 返回的值并合理地期望调用,例如Add(DateTime.Now),或Add(Thread.CurrentThread)。这就是IList 所承诺的。

这就是将您的列表复制到 List&lt;T&gt; 的原因 - List&lt;T&gt; 实现 两个 接口,并在使用不适当的参数类型调用其(显式实现的)IList 方法时抛出。

如果您可以通过返回 IEnumerable 而侥幸成功,请改为这样做。如果您可以改为返回IList&lt;MyDataRow&gt;,请执行此操作。如果你真的需要一个非泛型的IList 返回,那么实现接口并适当地处理非MyDataRow 值。

【讨论】:

  • +1 指出实施IList 和IList&lt;T&gt; 的危险
【解决方案4】:

要么在您的数据收集类上实现IList,要么创建一个适配器,它包装IList&lt;T&gt; 并实现IList:

public sealed class NonGenericList<T> : IList
{
    private readonly IList<T> _wrappedList;

    public NonGenericList(IList<T> wrappedList)
    {
        if(wrappedList == null) throw new ArgumentNullException("wrappedList");

        _wrappedList = wrappedList;
    }

    public int Add(object value)
    {
        _wrappedList.Add((T)value);
        return _wrappedList.Count - 1;
    }

    public void Clear()
    {
        _wrappedList.Clear();
    }

    public bool Contains(object value)
    {
        return _wrappedList.Contains((T)value);
    }

    public int IndexOf(object value)
    {
        return _wrappedList.IndexOf((T)value);
    }

    public void Insert(int index, object value)
    {
        _wrappedList.Insert(index, (T)value);
    }

    public bool IsFixedSize
    {
        get { return false; }
    }

    public bool IsReadOnly
    {
        get { return _wrappedList.IsReadOnly; }
    }

    public void Remove(object value)
    {
        _wrappedList.Remove((T)value);
    }

    public void RemoveAt(int index)
    {
        _wrappedList.RemoveAt(index);
    }

    public object this[int index]
    {
        get { return _wrappedList[index]; }
        set { _wrappedList[index] = (T)value; }
    }

    public void CopyTo(Array array, int index)
    {
        _wrappedList.CopyTo((T[])array, index);
    }

    public int Count
    {
        get { return _wrappedList.Count; }
    }

    public bool IsSynchronized
    {
        get { return false; }
    }

    public object SyncRoot
    {
        get { return this; }
    }

    public IEnumerator GetEnumerator()
    {
        return _wrappedList.GetEnumerator();
    }
}

用法:

public System.Collections.IList GetList()
{
    return new NonGenericList<MyDataRow>(this._mydata);
}

【讨论】:

    【解决方案5】:

    如果可以将IList&lt;T&gt; 直接转换为IList,则可以通过其Add(object) 方法返回一个可能(例如)被非T 对象“污染”的列表。

    【讨论】:

    • 您的第二段达到了关键,但第一段似乎有点偏离 - 编译错误的发生正是因为 IList&lt;T&gt; not 派生自 IList .
    • 好点。已作相应修改,感谢指正。你完全正确。
    猜你喜欢
    • 1970-01-01
    • 2013-01-11
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多