Reputation: 61057
I wrote some extensions methods to handle the css class like how you would do it in jQuery. Since I'm using ASP.NET the framework has two extension points i need to handle.
The first one is 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)
and the second one is 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)
the dilemma here has to do with that the CssClass property of WebControl doesn't seem to reflect accordingly when you access the property through the IAttributeAccessor interface.
i.e.
WebControl c;
c.CssClass = "hello-world";
Debug.Assert(((IAttributeSelector)c).GetAttribute("class") != "hello-world");
I did some digging around with the .NET Reflector and came to the conclusion that the assertion will hold. I can modify the same underlying HTML property class
in two distinct ways. Thus my problem, which overload do I use, or rather, which overload does the compiler use?
Now, System.Web.UI.WebControls.WebControl
implements System.Web.UI.IAttributeAccessor
and this is why I ask the question, which overload will be used? Or is the call ambiguous between the two?
I always imagine that the compiler/run-time calculated the distance to pick one type over the other.
Say TextBox
, which derives from WebControl
that implements IAttributeAccessor
would call the WebControl
overload because the distance to WebControl
is shorter, strictly speaking.
I found some stuff on MSDN about this, however, it doesn't say what it means to be better than or worse than. So what's going to happen when I call.
TextBox c;
c.AddCssClass("hello-world");
?
I ended up changing the IAttributeAccessor to HtmlControl instead, becuase it still covers most cases and would be less confusing for other developers on my team.
IntelliSense actually displayed both as possible overloads, while only one, in fact, is possible.
Upvotes: 1
Views: 293
Reputation: 1503489
You were nearly there - you wanted section 7.4.2.3 instead - "better conversion". It's not a matter of conversion "distance" though. (In the C# 3 spec this is 7.4.3.4 in case you're interested.)
The conversion from TextBox
to WebControl
is better than the conversion to IAttributeSelector
, because:
If an implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists, C1 is the better conversion.
There's an implicit conversion from WebControl
to IAttributeSelector
but not vice versa.
Now that we know which conversion is better, we can apply the section you referenced to determine that the overload with WebControl
will be picked. This can easily be demonstrated with a test application of course:
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();
}
}
This prints "Extension(Bar)" - corresponding to the extension method via WebControl
in your real case.
Of course, if you cast to b
to IFoo
then the overload printing "Extension(IFoo)" will be picked - because the compiler doesn't know that the other overload will be applicable. Remember that overloading is only performed at compile time (leaving aside dynamic
in C# 4).
Upvotes: 3