How do extension methods work with inheritance? - c#

I knew the first half part of the magic. Assume I have:
public class Foo {}
public class static FooExt
{
public static void M(this Foo f) {}
}
When I invoke foo.M() the compiler changes it to FooExt.M(foo).
But how about the inheritance? For example:
public class Bar : Foo {}
public class static BarExt
{
public static void M(this Bar b) {}
}
When I invoke bar.M() will it call FooExt.M() or BarExt.M()? In fact I tested it and the answer is BarExt, but why? What happens when I call wow.M() if I have another Wow : Foo but no WowExt.M()?

The compiler will look for the extension method whose arguments most closely match those at the invocation site. If you have a variable of type Bar then the BarExt extension would be used, since Bar is more specific a type than Foo, and therefore matches more closely than the alternative method that takes a Foo instance. This really is not very different from how ambiguous method overloads are resolved.
It is worth noting that this code will call FooExt.M():
Foo bar = new Bar();
bar.M();
This is because extension methods are not virtual. Since the variable you are invoking the method on is type Foo, the Bar version of the extension method will not even be considered. Binding of extension methods happens entirely at compile time.
In the second case you indicated (invoking the extension method on a variable of type Wow), the FooExt.M() method would be used, since there is nothing that matches better.

I tested it and the answer is BarExt, but why?
Because the compiler will choose the extension method that "best fits" the call. Since there is a method that takes a Bar directly, that one is chosen.
What happens when I call wow.M() if I have another Wow : Foo but no WowExt.M()?
Again, it will choose the extension that "best fits" the usage. Since there is no method that takes a Wow, but one that does take it's parent class Foo it will choose FooExt.M()
Remember that extension methods are really just syntactic sugar for static method calls, so the same rules apply to them as "normal" method resolution.

When resolving extension methods, the most specific type match will be selected. In your first case, BarExt.M() is the most specific (targets Bar rather than Foo).
In the second case, there is no Wow extension so the most specific match would be FooExt.M().

Related

Strange behavior from function overload resolution in c# with generics [duplicate]

The following program does not compile, because in the line with the error, the compiler chooses the method with a single T parameter as the resolution, which fails because the List<T> does not fit the generic constraints of a single T. The compiler does not recognize that there is another method that could be used. If I remove the single-T method, the compiler will correctly find the method for many objects.
I've read two blog posts about generic method resolution, one from JonSkeet here and another from Eric Lippert here, but I could not find an explanation or a way to solve my problem.
Obviously, having two methods with different names would work, but I like the fact that you have a single method for those cases.
namespace Test
{
using System.Collections.Generic;
public interface SomeInterface { }
public class SomeImplementation : SomeInterface { }
public static class ExtensionMethods
{
// comment out this line, to make the compiler chose the right method on the line that throws an error below
public static void Method<T>(this T parameter) where T : SomeInterface { }
public static void Method<T>(this IEnumerable<T> parameter) where T : SomeInterface { }
}
class Program
{
static void Main()
{
var instance = new SomeImplementation();
var instances = new List<SomeImplementation>();
// works
instance.Method();
// Error 1 The type 'System.Collections.Generic.List<Test.SomeImplementation>'
// cannot be used as type parameter 'T' in the generic type or method
// 'Test.ExtensionMethods.Method<T>(T)'. There is no implicit reference conversion
// from 'System.Collections.Generic.List<Test.SomeImplementation>' to 'Test.SomeInterface'.
instances.Method();
// works
(instances as IEnumerable<SomeImplementation>).Method();
}
}
}
Method resolution says that closer is better. See the blog post for exact rules.
What does the closer mean? Compiler will see if it can find exact match, if it can't find for some reason it will find next possible compatible methods and so forth.
Let's first make that method compile by removing the SomeInterface constraint.
public static class ExtensionMethods
{
public static void Method<T>(this T parameter) //where T : SomeInterface
{ }
public static void Method<T>(this IEnumerable<T> parameter) //where T : SomeInterface
{ }
}
Now compiler is happy to compile, and do note that both method calls Goes to Method(T) rather than Method(IEnumerable<T>). Why is that?
Because Method(T) is closer in the sense that can take any type as the parameter and also it doesn't require any conversion.
Why is Method(IEnumerable<T>) not closer?
It is because you have the compile time type of the variable as List<T>, so it needs a reference conversion from List<T> to IEnumerable<T>. Which is closer but far from doing no conversions at all.
Back to your question.
Why instances.Method(); doesn't compile?
Again, as said earlier to use Method(IEnumerable<T>) we need some reference conversion, so obviously that's not closer. Now we're left with only one method which is very closer is Method<T>. But the problem is you have constrained it with SomeInterface and clearly List<SomeImplementation>() is not convertible to SomeInterface.
The problem is (am guessing) checking for generic constraints happens after the compiler chooses the closer overload. That invalidates the chosen best overload in this case.
You could easily fix it by changing the static type of the variable to IEnumerable<SomeImplementation> that will work and now you know why.
IEnumerable<SomeImplementation> instances = new List<SomeImplementation>();
Have you tried implementing the first one without generics, as it should behave the same:
public static void Method(this SomeInterface parameter) { /*...*/ }
Or, as Dmitry suggested, by calling the second one the following way:
instances.Method<SomeImplementation>();
But here you need to add the <SomeImplementation> to every call...
While I know you dont want it, I think you should really re-think if method names should be the same. I cannot see how the same name can act on an instance, and collection of such instances. For eg, if your method name is Shoot for T, then the other method should sound like ShootThemAll or something similar.
Or else you should make your assignment slightly different:
IEnumerable<SomeImplementation> instances = new List<SomeImplementation>();
instances.Method(); //now this should work
As a last option, as Dimitry says in comments you have to explicitly specify the type argument.
instances.Method<SomeImplementation>();

Is there a reason why extension methods can't be invoked directly on "this"? [duplicate]

Can someone explain to me why in the following the 3rd invocation of DoSomething is invalid?
( Error message is "The name 'DoSomething' does not exist in the current context" )
public class A { }
public class B : A
{
public void WhyNotDirect()
{
var a = new A();
a.DoSomething(); // OK
this.DoSomething(); // OK
DoSomething(); // ?? Why Not
}
}
public static class A_Ext
{
public static void DoSomething(this A a)
{
Console.WriteLine("OK");
}
}
Extension methods can be invoked like other static methods.
Change it to A_Ext.DoSomething(this).
If you're asking why it isn't implicitly invoked on this, the answer is that that's the way the spec was written. I would assume that the reason is that calling it without a qualifier would be too misleading.
Because DoSomething takes a parameter.
DoSomething(a) would be legal.
Edit
I read the question a bit wrong here.
Since your calling it a a normal static method, and not a extension method, you need to prefic with the class name.
So A_Ext.DoSomething(a); will work.
If you call it like a normal static method, all the same rules apply.
Your second variant works because B inhetits A, and therefore you still end up calling it as an extension method, but the third does not.
sorry about the first version above that does not work. I'll leave it to keep the comment relevant.
Extension methods are still static methods, not true instance calls. In order for this to work you would need specific context using instance method syntax (from Extension Methods (C# Programming Guide))
In your code you invoke the extension
method with instance method syntax.
However, the intermediate language
(IL) generated by the compiler
translates your code into a call on
the static method. Therefore, the
principle of encapsulation is not
really being violated. In fact,
extension methods cannot access
private variables in the type they are
extending.
So while normally, both syntaxes would work, the second is without explicit context, and it would seem that the IL generated can't obtain the context implicitly.
DoSomething requires an instance of A to do anything, and without a qualifier, the compiler can't see which DoSomething you need to invoke. It doesn't know to check in A_Ext for your method unless you qualify it with this.

Why do I get this compile error trying to call a base constructor/method that takes a dynamic argument?

While refactoring some code, I came across this strange compile error:
The constructor call needs to be dynamically dispatched, but cannot be because it is part of a constructor initializer. Consider casting the dynamic arguments.
It seems to occur when trying to call base methods/constructors that take dynamic arguments. For example:
class ClassA
{
public ClassA(dynamic test)
{
Console.WriteLine("ClassA");
}
}
class ClassB : ClassA
{
public ClassB(dynamic test)
: base(test)
{
Console.WriteLine("ClassB");
}
}
It works if I cast the argument to object, like this:
public ClassB(dynamic test)
: base((object)test)
So, I'm a little confused. Why do I have to put this nasty cast in - why can't the compiler figure out what I mean?
The constructor chain has to be determined for certain at compile-time - the compiler has to pick an overload so that it can create valid IL. Whereas normally overload resolution (e.g. for method calls) can be deferred until execution time, that doesn't work for chained constructor calls.
EDIT: In "normal" C# code (before C# 4, basically), all overload resolution is performed at compile-time. However, when a member invocation involves a dynamic value, that is resolved at execution time. For example consider this:
using System;
class Program
{
static void Foo(int x)
{
Console.WriteLine("int!");
}
static void Foo(string x)
{
Console.WriteLine("string!");
}
static void Main(string[] args)
{
dynamic d = 10;
Foo(d);
}
}
The compiler doesn't emit a direct call to Foo here - it can't, because in the call Foo(d) it doesn't know which overload it would resolve to. Instead it emits code which does a sort of "just in time" mini-compilation to resolve the overload with the actual type of the value of d at execution time.
Now that doesn't work for constructor chaining, as valid IL has to contain a call to a specific base class constructor. (I don't know whether the dynamic version can't even be expressed in IL, or whether it can, but the result would be unverifiable.)
You could argue that the C# compiler should be able to tell that there's only actually one visible constructor which can be called, and that constructor will always be available... but once you start down that road, you end up with a language which is very complicated to specify. The C# designers usually take the position of having simpler rules which occasionally aren't as powerful as you'd like them to be.

Legacy API requires to pass callback name as string. Can I improve that API via an extension method?

I'm faced with a legacy API that doesn't use .NET events, but rather requires me to do this:
// (first arg is System.Object, second arg is string, myFoo is of type Foo)
myFoo.AddCallback(this, "DoSomething(int)");
This API requires that DoSomething be an instance method on this, and that it take an int.
Is there a way I can use force this API to be usable in a typesafe way?
More precisely: I want to write an extension method for Foo, which allows me to call AddCallback with a .NET delegate, rather than a receiver-signature pair. I'm imagining something like this:
// extension method definition
public static void AddCallback(this Foo foo, Action action)
{
foo.AddCallback(
FigureOutReceiverOf(action), // ?
FigureOutSignatureOf(action)); // ?
}
public static void AddCallback<T>(this Foo foo, Action<T> action)
{ ... } // and so on, for up to, say, 10 type-arguments
// usage:
myFoo.AddCallback(DoSomething)
// or even a lambda:
myFoo.AddCallback((i) => Console.WriteLine(i));
If it's possible to do this via an extension method hack, it would make my life better. Also I'm simply interested if it's possible given C#'s capabilities.
By the way, the legacy API is called qt4dotnet.
Using a lambda would be tricky - it will end up being a method in a different class, if it captures local variables. You could detect that, of course, but it wouldn't be compile-time safe.
Likewise the signature part is interesting, in that if it's definitely an Action, the delegate has no parameters. You can't just make the parameter Delegate, or method group conversions won't work... although you could still call
myFoo.AddCallBack(new Action<int>(MyMethodName));
An alternative is to produce a bunch of overloads:
public static void AddCallback(this Foo foo, Action action)
public static void AddCallback<T>(this Foo foo, Action<T> action)
public static void AddCallback<T1, T2>(this Foo foo, Action<T1, T2> action)
It wouldn't be elegant, but you'd probably only need a few for practical reasons. If any methods returned values, you'd need similar ones for Func.
There's the additional potential problem of passing a delegate with multiple actions... again, you could check this at compile-time. Finally, you might want to check that the Target of the delegate is the same as the foo parameter.
With these problems out of the way, working out the signature is relatively straightforward. You use the Delegate.Method property, and from that you can get the name and parameter types. If the library requires "int" rather than "System.Int32" etc then you'll need a bit of faffing around that, but it shouldn't be too bad. (It does sound like a pretty odd API though.)

How are extension methods compiled?

How the C# compiler implement extension methods?
The process is exactly the same as overload resolution:
Func(myObject);
The compiler checks all functions named "Func" and tries to match the static type of myObject to the parametrs (possibly using conversions, upcasting to base class). If it succeeds, then calls the appropriate function.
If you realize that you can call extensions methods "in a normal way", then it clears up:
static class MyExtensions
{
public static void MyFunc(this string arg)
{
// ...
}
}
string a = "aa";
MyExtensions.MyFunc(a); // OK
a.MyFunc(); // same as above, but nicer
For the given type (here string), the compiler just looks for all static functions with "this" modifier on the first argument and tries to match the static type on the left of the . (in this example "a") with the parameter type in the function.
Instance methods of a class have a hidden argument. An example:
class Example {
public void Foo(int arg) {}
}
actually looks like this when the JIT compiler is done with it, converted back to C# syntax:
static void Foo(Example this, int arg) {}
That hidden argument is the reason that you can use this in an instance method. The JIT compiler figures out the argument to pass from the object reference you provide to call the Foo method.
As you can tell, it is now a very short hop to an extension method.
The compiler first looks in the base class for a function matching the signature of the function. If it can't find it than it looks for an extension. If an extension has the same signature as a base class method than the base class method is called instead.
This might help:
Extension Methods

Categories