我无法让C#编译器调用我创建的扩展方法,因为它更喜欢带有params
参数的实例方法。
例如,假设我有以下类及其方法:
public class C
{
public void Trace(string format, params object[] args)
{
Console.WriteLine("Called instance method.");
}
}
和扩展名:
public static class CExtensions
{
public void Trace(this C @this, string category, string message, params Tuple<string, decimal>[] indicators)
{
Console.WriteLine("Called extension method.");
}
}
在我的示例程序中:
public void Main()
{
var c = new C();
c.Trace("Message");
c.Trace("Message: {0}", "foo");
c.Trace("Category", "Message", new KeyValuePair<string, decimal>("key", 123));
}
所有来电都打印Called instance method.
。
显然,我没有访问类C
,或者我不打算创建扩展方法,我的扩展很重要,因为它允许我的用户继续使用他们已经知道的类增值。
从我的理解,编译器将优先于扩展方法的实例方法,但这是唯一的规则吗?这意味着任何具有类似Method(string format, params object[] args)
的方法的类都不能使用类型为string
的第一个参数的扩展方法。
对于此行为的原因或解决方法的原因(即不“只需致电CExtensions.Trace(c, "Category", ...
”)的任何解释都将非常感谢。
答案 0 :(得分:5)
您不能使用扩展来“接管”现有的类方法。
如果呼叫在没有扩展名的情况下有效,则添加扩展名时不应更改行为。原因是现有代码不应该通过稍后引入扩展来破解。
您必须为其使用不同的名称,或使用与类方法不同的参数类型。
答案 1 :(得分:4)
你不能直接。目标实例上的方法总是优于扩展方法。执行此操作的唯一方式(同时保持名称相同等)是使用CExtensions.Trace
方法(在问题中)。
在某些情况下,这里的一个技巧是使用C
的基类或C
实现的接口,但没有 a {{1方法,并重新键入变量,并在Trace
上添加重载,即
CExtensions
答案 2 :(得分:2)
Tuple<string, decimal>
与KeyValuePair<string, decimal>
不同。因此,传入的KeyValuePair<string, decimal>
仅作为对象使用,因此使用了params object[] args
的成员方法。
事实上,KeyValuePair
是结构。
答案 3 :(得分:2)
您可以使用命名参数:
c.Trace(
"Category",
"Message",
indicators: new Tuple<string, decimal>("key", 123));
但是你放弃了params
功能,你需要为indicators参数显式传递一个数组,如下所示:
c.Trace(
"Category",
"Message",
indicators: new Tuple<string, decimal>[]
{
new Tuple<string, decimal>("key", 123),
new Tuple<string, decimal>("key2", 123)
});
答案 4 :(得分:0)
我猜您可以更改第一个参数类型或函数名称(TraceFormat
?)
这个params版本看起来非常贪婪,所以如果你将第一个参数保存为字符串,它将始终捕获所有调用并忽略我认为的扩展方法。