简体   繁体   English

在特殊情况下解决通用和非通用IList扩展方法之间的歧义调用

[英]Resolve ambiguous calls between a generic and a non-generic IList extension method in special circumstances

I have an extension function called RemoveWhere . 我有一个名为RemoveWhere的扩展功能。 It simply accepts a predicate and removes items from a list which satisfy the condition. 它仅接受谓词并从满足条件的列表中删除项目。 I removed the implementation for clarity. 为了清楚起见,我删除了实现。

public static IList<object> RemoveWhere(this IList list, Func<object, bool> predicate, int offset = 0)
{
    ...
}

public static IList<T> RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate, int offset = 0)
{
    ...
}

I needed this method for generic IList<T> and non-generic IList as well, because we have several scenarios where only a non-generic interface is available. 对于通用IList<T>和非通用IList ,我也需要此方法,因为我们有几种方案,其中只有非通用接口可用。

However, when I have a specific List<T> instance, I get an ambiguous call compile-time error because it implements both the generic and non-generic interface. 但是,当我有一个特定的List<T>实例时,我会得到一个模棱两可的调用编译时错误,因为它同时实现了通用和非通用接口。

How could I resolve it without renaming one of the methods? 如何在不重命名其中一种方法的情况下解决该问题?

UPDATE 更新

I'm looking for a general solution which would apply to all collections which possibly implement both interfaces. 我正在寻找一种通用的解决方案,该解决方案将应用于可能实现两个接口的所有集合。 I currently use Visual Studio 2013 and targeting .NET 4. 我目前使用Visual Studio 2013,并定位.NET 4。

UPDATE 2 更新2

It turns out that the ambiguous call issue only appears when I don't reference any member of T directly in the predicate. 事实证明,仅当我没有在谓词中直接引用T任何成员时,模棱两可的调用问题才会出现。 Example here. 这里的例子。

class Person {}
class SpecialPerson : Person {}

var list = new List<Person>();
// this resolves to the generic version
list.RemoveWhere(e => e.Name.Contains("Peter");
// this gives ambiguous call compiler error
list.RemoveWhere(e => e is SpecialPerson);

If have tested this code and it calls the correct Extension for the different type: 如果已经测试了此代码,并且为其他类型调用了正确的扩展:

class Program
{
    static void Main(string[] args)
    {
        var genericList = new List<String>() {"a", "b"};
        var listImplementation = new MyList();

        var resultGeneric = genericList.RemoveWhere(x => x.Contains("s"));
        var resultImplemented = listImplementation.RemoveWhere(x => x.Equals(1));
    }
}

class MyList : IList
{
   ...
}

public static class JTest
{
    public static IList RemoveWhere(this IList list, Func<object, bool> predicate, int offset = 0)
    {
        return list;
    }

    public static IList<T> RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate, int offset = 0)
    {
        return list;
    }
}

You could introduce a third overload(!) which calls the right one, as in: 您可以引入第三个重载(!)来调用正确的重载,如:

public static IList<T> RemoveWhere<T>(this List<T> list, Func<T, bool> predicate, int offset = 0)
{
  return ((IList<T>)list).RemoveWhere(prdeicate, offset);
}

For this special case when I don't reference any member of T in the predicate I ended up adding the generic parameter to the call, helping out the compiler. 对于这种特殊情况,当我在谓词中没有引用T任何成员时,我最终将泛型参数添加到调用中,从而帮助了编译器。

class Person {}
class SpecialPerson : Person {}

var list = new List<Person>();
// this resolves to the generic version
list.RemoveWhere(e => e.Name.Contains("Peter");
// this gives ambiguous call compiler error
list.RemoveWhere(e => e is SpecialPerson);
// if I help the compiler it resolves correctly
list.RemoveWhere<Person>(e => e is SpecialPerson);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM