通用列表:无法从lambda中的用法推断出方法的类型参数

时间:2014-10-24 13:36:15

标签: c# linq interface lambda

我在C#中遇到了一个问题,给我一个错误'无法从使用中推断出方法的类型参数'。如果我从非泛型列表派生通用列表,似乎编译器无法确定正确的接口:

代码:

public class SpecialItem : BaseItem
{
    public string Title { get; set; }
}

public class BaseItem
{
    public string Name { get; set; }
}


public class GenericList<T> : NongenericBaseList, IEnumerable<T>
    where T: BaseItem
{
    public new T this[int index]
    {
        get { return _items[index] as T; }
    }

    public new IEnumerator<T> GetEnumerator()
    {
        var iter = _items.GetEnumerator();
        while (iter.MoveNext())
        {
            yield return iter.Current as T;
        }
    }
}


public class NongenericBaseList : IEnumerable<BaseItem>
{
    protected List<BaseItem> _items;

    public BaseItem this[int index]
    {
        get { return _items[index]; }
    }

    public IEnumerator<BaseItem> GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

用法:

    var genericList = new GenericList<SpecialItem>();
    foreach (var item in genericList)  // Uses IEnmerable<SpecialItem>, OK!
    {
        Console.WriteLine(item.Title);
    }

    var l = genericList.ToList();  // ERROR!

ForEarch获取正确的Enumerator(SpecialItem),但lambda不知道要使用什么(IEnumerable<BaseItem>IEnumerable<SpecialItem>)。

怎么办?如何将IEnumerable<SpecialItem>设置为“默认”界面?我不想像这样明确地对类型进行编码:

var l = genericList.ToList<SpecialItem>();

2 个答案:

答案 0 :(得分:1)

首先:赞扬提供一个独立的例子!

您无法指定&#39;默认&#39;类型推断的接口。 ToList<T>的参数类型无法解析,因为它不明确,类型同时实现IEnumerable<BaseItem>IEnumerable<SpecialItem>,并且这两个版本都适用。

是否有可能完全删除课程NongenericBaseList,而是使用GenericList<T>?这可以解决你的问题;您可以使用GenericList<BaseItem>代替NongenericBaseList

另一种选择是扭转继承;将NongenericBaseList设为空并从GenericList<BaseItem>派生。

答案 1 :(得分:0)

感谢Sriram Sakthivel,他引导我找到一个开销非常小的解决方案。为了清楚起见,我想确保:

  1. 两个列表,通用列表和非泛型列表必须是同一个对象。因此,我必须得出,而不是包装在包装中。
  2. 两个列表都必须支持通过循环(ForEach)和lambdas / extension方法进行访问,而无需显式输入类名。
  3. 他们必须实施IList<T>,因此T out不是一种选择。
  4. 简而言之,以下代码必须编译而不会出错:

    // Generic
    var genericList = new GenericList<SpecialItem>();
    foreach (var item in genericList)
    {
        Console.WriteLine(item.Title);
    }
    
    var l = genericList.ToList();
    
    // Nongeneric
    var nongenericList = genericList as NongenericBaseList;
    foreach (var item in nongenericList)
    {
        Console.WriteLine(item.Name);
    }
    
    var nl = nongenericList.ToList();
    

    我得出的结论是,对于上面的代码,这是不可能的(如果不是这样,请纠正我!)。循环工作正常,但泛型或非泛型列表不适用于.ToList()或其他扩展方法,因为编译器无法推断出类型。

    现在我使用了Sriram Sakthivel tipp,仅使用IEnumerable而不使用<T>。但即使您明确地写出类型,所有人都无法使用扩展方法。

    我只是添加了一个属性,转换集合:

    public class NongenericBaseList : IEnumerable  // Without the T!
    {
        protected List<BaseItem> _items;
    
        // The property
        public IEnumerable<BaseItem> L
        {
            get { return this as IEnumerable<BaseItem>; }
        }
    
        public BaseItem this[int index]
        {
            get { return _items[index]; }
        }
    
        public IEnumerator<BaseItem> GetEnumerator()
        {
            return _items.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    

    现在我可以输入:

    var nl = nongenericList.L.ToList();
    

    任何更好的解决方案都将不胜感激!