C#调用时,通用静态调用错误
我有一个通用扩展方法,如下所示:C#调用时,通用静态调用错误,c#,.net,extension-methods,C#,.net,Extension Methods,我有一个通用扩展方法,如下所示: public static class Validator { public static IEnumerable<string> Validate<T>(IList<T> items) { foreach (var item in items) { var result = MyValidator.Validate(item);
public static class Validator
{
public static IEnumerable<string> Validate<T>(IList<T> items)
{
foreach (var item in items)
{
var result = MyValidator.Validate(item);
if (!result.Any()) continue;
foreach (var validationResult in result)
yield return validationResult.ErrorMessage;
}
}
public static IEnumerable<string> Validate<T>(T item)
{
var result = MyValidator.Validate(item);
if (!result.Any()) yield break;
foreach (var validationResult in result)
yield return validationResult.ErrorMessage;
}
}
公共静态类验证程序
{
公共静态IEnumerable验证(IList项)
{
foreach(项目中的var项目)
{
var result=MyValidator.Validate(项目);
如果(!result.Any())继续;
foreach(结果中的var validationResult)
产生返回validationResult.ErrorMessage;
}
}
公共静态IEnumerable验证(T项)
{
var result=MyValidator.Validate(项目);
如果(!result.Any())产生中断;
foreach(结果中的var validationResult)
产生返回validationResult.ErrorMessage;
}
}
但是当我为单个对象或集合调用方法时,它调用Validate(T item)
var item=newperson();
var items=新列表();
var v1=验证器。验证(项目);//调用验证(T项)
var v2=验证器。验证(项目);//调用Validate(T项),但应调用Validate(IList项)
我想调用Validate(IList项)
查看列表
出现此问题的原因?这些扩展方法具有相似的签名-
IList项
是T项
将
Validate(IList项)
重命名为ValidateList(IList项)
或将Validate(T项)
重命名为ValidateItem(T项)
将提供您要查找的结果。这是因为接口在重载解析中的优先级低于具体类型
正如@JonSkeet指出的,这可能是因为从
T
到T
的类型转换比从List
到IList
的类型转换更好,所以编译器选择泛型重载
在您的例子中,您可以通过将方法的参数从IList
更改为List
来获得所需的行为
公共接口IFoo{}
公共类Foo:IFoo{}
公共静态类验证器
{
公共静态void方法(T){}
公共静态void方法(对象o){}
公共静态无效方法(IFoo i){}
}
静态void Main()
{
var foo=new foo();
方法(foo);//调用方法(T)
对象o=foo;
方法(o);//显式对象,调用方法(对象o)
IFoo i=foo;
方法(i);//显式接口,调用方法(ifooi)
}
var v1=Validator.Validate(新列表(){item});它不是一个扩展方法,除非您将它的第一个参数声明为this IList items
,而且,您似乎有一个递归<代码>验证(T项)调用自身:item.Validate()
。由于T
没有通用约束,Validate
不能是项的成员。这是否回答了您的问题?我建议将其中一种方法重命名,最好是将列表的方法重命名为类似于ValidateList
的方法。这不是原因,请参阅建议的副本。名称相同但参数不同“这是因为接口在重载解析中的优先级低于具体类型。”不,这不是事实。这是因为在对第一个方法的调用中,转换是从List
到IList
;第二个是从T
到T
。后者是首选的,因为类型是相同的-如果items
已声明为IList
,则将使用第一种方法。@JonSkeet如果我不准确,很抱歉,您是否有解释解决方案的文档链接?我找不到,所以我测试了我的假设shown@JonSkeet将方法声明为Validate(IList items)
似乎无法战胜Validate(t item)
,而Validate(List items)
则是。是的,但这并不是因为IList
是一个接口<代码>验证(对象)
的工作方式也一样。基本上,有关重载解析和“更好的转换”一节中的语言规范中都有详细说明。
var item = new Person();
var items = new List<Person>();
var v1 = Validator.Validate(item); // calls Validate<T>(T item)
var v2 = Validator.Validate(items); // calls Validate<T>(T item) but should call Validate<T>(IList<T> items)