C# 调用哪个重载以及如何调用?

C# 调用哪个重载以及如何调用?,c#,.net,C#,.net,我编写了一些扩展方法来处理css类,就像在jQuery中那样。因为我使用的是ASP.NET,所以这个框架有两个扩展点需要处理 第一个是System.Web.UI.WebControls.WebControl public static bool HasCssClass(this WebControl control, string className) public static void AddCssClass(this WebControl control, string className

我编写了一些扩展方法来处理css类,就像在jQuery中那样。因为我使用的是ASP.NET,所以这个框架有两个扩展点需要处理

第一个是
System.Web.UI.WebControls.WebControl

public static bool HasCssClass(this WebControl control, string className)
public static void AddCssClass(this WebControl control, string className)
public static void RemoveCssClass(this WebControl control, string className)
第二个是System.Web.UI.IAttributeAccessor

public static bool HasCssClass(this IAttributeAccessor accessor, string className)
public static void AddCssClass(this IAttributeAccessor accessor, string className)
public static void RemoveCssClass(this IAttributeAccessor accessor, string className)
这里的困境在于,当您通过IAttributeAccessor接口访问该属性时,WebControl的CssClass属性似乎没有相应地反映出来

i、 e

我对.NET Reflector做了一些深入的研究,得出结论认为这个断言是正确的。我可以用两种不同的方式修改相同的底层HTML属性
class
。因此,我的问题是,我使用哪个重载,或者更确切地说,编译器使用哪个重载

现在,
System.Web.UI.WebControls.WebControl
实现
System.Web.UI.iaTributeAccessor
,这就是为什么我要问这个问题,将使用哪个重载?还是两者之间的通话模棱两可

我总是想象编译器/运行时计算了选择一种类型与另一种类型之间的距离

如果说
TextBox
,它源于实现
IAttributeAccessor
WebControl
,将调用
WebControl
重载,因为严格来说,到
WebControl
的距离较短

我发现了一些关于这方面的东西,但是,它并没有说明什么是比好还是比坏。我打电话的时候会发生什么

TextBox c;
c.AddCssClass("hello-world");
?

编辑 我最终将IAttributeAccessor改为HtmlControl,因为它仍然涵盖了大多数情况,而且对我团队中的其他开发人员来说也不会那么混乱


IntelliSense实际上将这两种重载都显示为可能的重载,而事实上,只有一种重载是可能的。

您就快到了—您想要的是“更好的转换”部分。但这不是转换“距离”的问题。(在C#3规范中,如果您感兴趣,这是7.4.3.4。)

TextBox
WebControl
的转换比到
IAttributeSelector
的转换要好,因为:

如果存在从T1到T2的隐式转换,并且没有从T2到T1的隐式转换 存在时,C1是较好的转换

存在从
WebControl
IAttributeSelector
的隐式转换,但反之亦然

现在我们知道了哪种转换更好,我们可以应用您引用的部分来确定将选择带有
WebControl
的重载。当然,这可以通过测试应用程序轻松演示:

using System;

public interface IFoo {}
public class Bar : IFoo {}
public class Baz : Bar {}

public static class Extensions
{
    public static void Extension(this IFoo foo)
    {
        Console.WriteLine("Extension(IFoo)");
    }

    public static void Extension(this Bar bar)
    {
        Console.WriteLine("Extension(Bar)");
    }
}

public class Test
{
    static void Main()
    {
        Baz b = new Baz();
        b.Extension();
    }
}
这将打印“扩展(条)”-对应于实际案例中通过
WebControl
的扩展方法


当然,如果您强制转换到
b
IFoo
,则会选择重载打印“Extension(IFoo)”——因为编译器不知道其他重载是否适用。记住重载只在编译时执行(撇开C#4中的
dynamic

我想我明白了,但我不得不写了好几次才明白。T1为网络控制,T2为IAttributeAccessor,S为文本框,具有到两者的隐式转换,但IAttributeAccessor没有到网络控制的隐式转换。T1是一种类型。你知道这个有没有正式的名字吗?和往常一样,我很惊讶你能抽出时间回答所有这些问题;)谢谢但是如果T1是T2,但是T2不是T1,这不是意味着距离吗?当距离相同时,有一条规则可以解决歧义,但距离参数在某种程度上似乎是正确的。@约翰:我怀疑你可以通过“距离”类比和直觉走得很远,但我更喜欢处理规范中的术语-它们更容易推理,这是沟通的一个常见参考框架。我肯定会有一些“距离”类比不适用的角落案例。至于正式的名字——确切地说是什么名字?重载解析,确定“更好”的函数成员,确定“更好”的转换?同意,我只是从类型理论的角度思考,如果这是一种众所周知的处理重载解析的方法。约翰:每种语言都有自己的一套规则,它们可能会有细微的差别。当在派生类中引入重载时,它会变得更有趣。。。看看这里的第一个例子,例如:那太邪恶了。。。S是int,我看不到。是什么让object更适合重载,这显然反驳了距离的论点。无论如何,当我读到这篇文章时,如果S是T1,C1是更好的转换。我看着它,想,这意味着没有转换发生,当你反转它时,如果S是T2,C2是更好的转换,那么这意味着一个歧义。7.4.2.3中未提及歧义。这不可能,然后我看了7.4.2.2,得出结论,要编译这个,至少有一个参数必须有更好的转换。也就是说,拳击在某种程度上是一种更好的转换。
using System;

public interface IFoo {}
public class Bar : IFoo {}
public class Baz : Bar {}

public static class Extensions
{
    public static void Extension(this IFoo foo)
    {
        Console.WriteLine("Extension(IFoo)");
    }

    public static void Extension(this Bar bar)
    {
        Console.WriteLine("Extension(Bar)");
    }
}

public class Test
{
    static void Main()
    {
        Baz b = new Baz();
        b.Extension();
    }
}