如何使用params强制使用扩展方法而不是实例方法?

时间:2011-11-08 10:06:53

标签: c# extension-methods

我无法让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", ...”)的任何解释都将非常感谢。

5 个答案:

答案 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版本看起来非常贪婪,所以如果你将第一个参数保存为字符串,它将始终捕获所有调用并忽略我认为的扩展方法。