解决特殊情况下泛型和非泛型 IList 扩展方法之间的模糊调用
Resolve ambiguous calls between a generic and a non-generic IList extension method in special circumstances
我有一个名为 RemoveWhere
的扩展函数。它只是接受一个谓词并从满足条件的列表中删除项目。为了清楚起见,我删除了实现。
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)
{
...
}
我也需要这种方法用于泛型 IList<T>
和非泛型 IList
,因为我们有几种情况只有非泛型接口可用。
但是,当我有一个特定的 List<T>
实例时,我得到一个模糊调用编译时错误,因为它同时实现了通用接口和非通用接口。
如何在不重命名其中一种方法的情况下解决它?
更新
我正在寻找适用于所有可能实现这两个接口的集合的通用解决方案。我目前使用 Visual Studio 2013 并以 .NET 4 为目标。
更新 2
事实证明,只有在谓词中没有直接引用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);
您可以引入第三个重载 (!) 来调用正确的重载,如:
public static IList<T> RemoveWhere<T>(this List<T> list, Func<T, bool> predicate, int offset = 0)
{
return ((IList<T>)list).RemoveWhere(prdeicate, offset);
}
如果测试了此代码并且它为不同类型调用了正确的扩展:
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;
}
}
对于这种特殊情况,当我没有在谓词中引用 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);
我有一个名为 RemoveWhere
的扩展函数。它只是接受一个谓词并从满足条件的列表中删除项目。为了清楚起见,我删除了实现。
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)
{
...
}
我也需要这种方法用于泛型 IList<T>
和非泛型 IList
,因为我们有几种情况只有非泛型接口可用。
但是,当我有一个特定的 List<T>
实例时,我得到一个模糊调用编译时错误,因为它同时实现了通用接口和非通用接口。
如何在不重命名其中一种方法的情况下解决它?
更新
我正在寻找适用于所有可能实现这两个接口的集合的通用解决方案。我目前使用 Visual Studio 2013 并以 .NET 4 为目标。
更新 2
事实证明,只有在谓词中没有直接引用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);
您可以引入第三个重载 (!) 来调用正确的重载,如:
public static IList<T> RemoveWhere<T>(this List<T> list, Func<T, bool> predicate, int offset = 0)
{
return ((IList<T>)list).RemoveWhere(prdeicate, offset);
}
如果测试了此代码并且它为不同类型调用了正确的扩展:
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;
}
}
对于这种特殊情况,当我没有在谓词中引用 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);