调用哪个重载以及如何?

时间:2010-01-10 17:43:28

标签: 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)
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)

这里的困境与WebControl的CssClass属性在通过IAttributeAccessor接口访问属性时似乎没有相应的反映有关。

WebControl c;
c.CssClass = "hello-world";
Debug.Assert(((IAttributeSelector)c).GetAttribute("class") != "hello-world");

我用.NET Reflector进行了一些挖掘,并得出结论,断言将成立。我可以用两种不同的方式修改相同的底层HTML属性class。因此我的问题是,我使用哪个重载,或者更确切地说,编译器使用哪个重载?

现在,System.Web.UI.WebControls.WebControl实现System.Web.UI.IAttributeAccessor这就是为什么我问这个问题,会使用哪个重载?或者两者之间的呼叫是否含糊不清?

我总是想象编译器/运行时计算选择一种类型而不是另一种类型的距离。

来自实施TextBox的{​​{1}}派生的WebControl会调用IAttributeAccessor重载,因为到WebControl的距离较短,严格来说。 / p>

我在MSDN上发现了一些关于此问题的内容,然而,它没有说明比什么更好或者更糟糕。那么当我打电话时会发生什么。

WebControl

修改

我最终将IAttributeAccessor更改为HtmlControl,因为它仍然涵盖了大多数情况,并且对我团队中的其他开发人员来说不那么容易混淆。

IntelliSense实际上都显示为可能的重载,而实际上只有一个是可能的。

1 个答案:

答案 0 :(得分:3)

你几乎就在那里 - 你想要部分7.4.2.3 - “更好的转换”。这不是转换“距离”的问题。 (在C#3规范中,如果您感兴趣,这是7.4.3.4。)

TextBoxWebControl的转换优于转换为IAttributeSelector,因为:

  

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

WebControlIAttributeSelector的隐式转换,但反之亦然。

现在我们知道哪个转换更好,我们可以应用您引用的部分来确定将选择带有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对应于扩展方法。

当然,如果你强制转换为bIFoo,那么将选择过载打印“Extension(IFoo)” - 因为编译器不知道其他过载是否适用。请记住,重载仅在 在编译时执行(在C#4中保留dynamic)。