具有参数数组的泛型 C# 方法重载解析
本文关键字:方法 重载 泛型 参数 数组 | 更新日期: 2023-09-27 18:34:36
在下面的代码中,我定义了两个名为 Bar
的重载方法。在Foo()
中,我向Bar
进行了三次调用,并在第三次调用时出现错误。
前两个解析为预期的重载。但是,第三个生成了以下错误:
The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Bar<T>(T, string, params object[])'. There is no implicit reference conversion from 'string' to 'System.Exception'.
显然,第三次调用绑定到 "Bar((",但无法将第一个参数转换为异常。同样清楚的是,第二个参数是一个抛弃编译器的字符串。当它不是字符串(大小写 2(时,分辨率很好。但是很明显(对我来说(失败的行应该绑定到"Bar(("(因为第一个参数明确是一个字符串(。
谁能解释为什么编译器使用此绑定?我会考虑创造性的解决方法,但我真正想要的是解释为什么会发生这种情况。我花了一些时间研究 C# 语言规范,但未能找到(即放弃(一个明确的答案。显然,我可以重命名Bar
方法之一,或提供命名参数,或将其中一个参数标记为ref
......但这些都不适合我的特定场景。
并不是说它相关,但是我已经编写了正是这样做的Java代码,编译器没有问题。
代码:
public void Bar(string s, params object[] ps) { } // Call this "Bar()"
public void Bar<E>(E e, string s, params object[] ps) where E : Exception { } // Call this "Bar<T>()"
public void Foo()
{
Exception e;
Object o1, o2;
Bar(e, "fmt {0}", o); // Resolves fine, as expected
Bar("fmt {0} {2}", o1, o2); // Also resolves as expected
Bar("fmt {0} {2}", "bar", o1); // Error!
}
答案是重载匹配不考虑约束。至于这是否在 C# 规范中,我不完全确定。匹配始终使用最具体的选项和字符串作为泛型T
始终比Object
字符串更具体(因为它匹配的是实际类型而不是子类型(。请参阅约束不是 Eric Lippert 博客上签名的一部分。
若要执行此操作,如果需要异常约束,请尽可能使用 void Bar(Exception E, ...)
。
Bar("fmt {0} {2}", "bar", o1);
//错误!通过特异性优先级,它查找方法签名,其中第二个参数是字符串(字符串比对象更具体(,然后尝试解析 Type 参数,但它无法解析。为了说明这一点,请尝试将第三个调用替换为:
Bar("fmt {0} {2}", (object)"bar", o1); // Now it is fine for compiler!