What are we extending when creating a generic extension method? - c#

public static class MyClass
{
public static void Print<T>(this T theObject)
{
Console.WriteLine("The print output is " + theObject.ToString());
}
}
In the given class I've specified a generic as the type to extend via the this keyword. Being that I've delayed the definition of the type until compile time, how does intellisense (and anything else involved) know what type I am extending? Does C# simply default to the top level System.Object?

Yes, it's System.Object unless you add a type constraint.

Being that I've delayed the definition of the type until compile time, how does intellisense (and anything else involved) know what type I am extending? Does C# simply default to the top level System.Object?
Those that say that this is an extension on System.Object are wrong. For one, this method will not box value type inputs, but an extension method defined on System.Object will.
The extension method you've defined is an generically parameterized extension method. It can be applied to any type that is valid as generic type parameter.
If you're not already thinking about extension methods in the following way, this might help you understand them a little bit better. Extension methods are just a trick that the language specification lets us get away with. Extension methods are really just static methods in static classes that we can call as if they were instance methods. So
static class Foo {
public static void M(this object obj) { }
}
is just a static method in a static class. You could call it like this:
Foo.M(obj);
but we can call it like it's an instance method:
obj.M();
Thus, when you have a generic extension method, stop for a minute and think about it as a static method in a static class
static class Foo {
public static void M<T>(this T obj) { }
}
You could call it like this:
object obj;
Foo.M(obj);
or you can call it like this:
obj.M();
There's no difference to the compiler which you write.
So, now you're thinking of it as a regular generic method. But surely when you think about it from this perspective you understand that the compiler will let you invoke this method on any type that is valid as a generic type parameter. And thus, you now understand why it can be thought of as an extension method on any type that is valid as a generic type parameter.

Related

Extension Methods and method overriding

The other day I found this statement in a stackoverflow post relating to Extension Methods:
The main thing there is ability to override different methods based on different generic’s parameters instantiation. This is similar to Haskell’s type classes
Java equivalent to C# extension methods
What's that supposed to mean? Can anybody give a significant example which clarifies this statement?
I'd assume that they're referring to the fact that C#'s compiler will choose the method that most narrowly defines the type. So for example if you have a abstract class (ABS) and a inherited class (CLS2) and 2 extension methods
public static object GetStuff(this ABS obj){
blah blah blah
}
public static object GetStuff(this CLS obj){
blah blah blah
}
if you call the CLS2.GetStuff() the compiler will choose the second method. Once you know that you can take "Override" an extension method by making it more specific. So if you have a generic class
public class Foo<T>{}
You could make 2 extension methods (using classes from above as types)
public static void DoSomething(this Foo<Abs> abs){}
and
public static void DoSomething(this Foo<CLS2> abs){}
Here the second method is "Overriding" the more "generic" abstract type.
This is ony possible with C# because it actually generates a new class for every Generic type. With a language like Java where it uses "Type Erasure Generics" you can't "overload" generic method since everything is really type Object under the hood.

How to create a generic extension method with additional type for generic interface

Today I encountered a small problem, and unfortunately I have not found a good solution. I would like to create a extension method for some generic interface. This method accepts a different type of a generic parameter, as seen below
public interface IGenericInterface<TSource>
{
void DoSomething<TDest>();
}
DotNetFiddle
How to call a DoSomething2 method exactly in the same way as DoSomething method (without passing first type)?
public void DoSomething<TDest>()
//Called like below
testClass.DoSomething<object>();
instead of (like my current signature)
public static void DoSomething2<TDest, TSource>(this IGenericInterface<TSource> interf)
//called like below
testClass.DoSomething2<string, object>(); // have to repass object type
I know that the compiler can not automatically infer the second type (link). But I'm curious if anyone has found a solution.
Your problem is the argument - you're depending on type inference to handle the first generic type, but then you want to explicitly specify the second one - that just isn't possible in C#.
Instead, why not change the type of the argument?
public static void DoSomething3<T, T2>(this IGenericInterface<T> interf, T2 parameter)
//called like below
testClass.DoSomething3((object)3);
With this, T is inferred based on testClass (as long as it's not ambiguous), and T2 is inferred based on (object)3.

What is difference between extension method and static method?

What is the difference between an extension method and a static method ?
I have two classes like this :
public static class AClass {
public static int AMethod(string ....)
{
}
}
and
public static class BClass {
public static int BMethod(this string ....)
{
}
}
I can use these like
AClass.AMethod('...');
or
'...'.BMethod();
Which is proposed ?
An extension method is still a static method. You can use it exactly as you'd use a normal static method.
The only difference is that an extension method allows you to use the method in a way that looks like it's part of the type, so you can write:
int result = stringValue.BMethod();
Instead of:
int result = BClass.BMethod(stringValue);
This works purely as a compile "trick" - the compiler sees the first form, and if the BClass is usable (it has a proper using and is in a referenced assembly), then it will turn it into the second method's IL for you. It's purely a convenience.
Which is proposed ?
This really depends. If you control the type, I'd recommend putting the methods on the type itself. This is typically more maintainable.
If you don't control the type, or you're trying to "extend" a common type (such as IEnumerable<T>), then extension methods may be a reasonable approach.
However, if the type is a very common type, I'd typically avoid extension methods, as they become "noise" in intellisense, which in turn can cause extra confusion. For example, I would personally not recommend adding extension methods on System.Object or System.String, etc.
You cannot override an extension method.
Only if the method has a different signature, then it can be overloaded.
Off course there are some limitations:
Extension Methods have to be implemented as static methods and in static classes (inside a non-nested, non-generic static class to be more precise).
You can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called. At compile time, extension methods always have lower priority than instance methods defined in the type itself.
Extension methods cannot access private variables in the type they are extending.
You can consider Extension Methods as a 'legal' way to add more static methods to existing classes without actually inheriting them.
But the funny thing is that unlike regular static methods of the class, you cannot call Extension Methods on a class level (you will get an compile time error if you try this), but instead you must invoke them on a instance of the class (as if they were some regular methods of the instance of that class, which they are not!!!).
Also, inside the Extension Method you can freely use public properties of the passed object instance on which the method is being invoked, you are by no means limited only to static object data. Only the Extension Method is static method, but the object on which is called is full, regular object instance.

Extension method vs static method precedence

Consider the following program:
class A
{
public static void Foo()
{
}
}
static class Ext
{
public static void Foo(this A a)
{
}
}
class Program
{
static void Main(string[] args)
{
var a = new A();
a.Foo();
}
}
This fails to compile, with the error:
Member 'Test.A.Foo()' cannot be accessed with an instance reference; qualify it with a type name instead
Why is the compiler ignoring the extension method?
What you are trying to do isn't allowed. The C# MSDN Extension Method Article specifically states that:
You can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called. At compile time, extension methods always have lower priority than instance methods defined in the type itself.
Thank goodness it isn't allowed as that would just be awful to have to maintain.
EDIT: So people are saying that static methods aren't instance methods, which is correct. But try doing this:
class A
{
public static void Foo() {}
public void Foo() {}
}
That won't compile either because of a name ambiguity. That is exactly what would happen if you were allowed to use the extension method. It would introduce the exact same ambiguity. Now, given that one method is static and one is instance, should that mean that there is no ambiguity, perhaps. But at the current state it does introduce ambiguity which is yet another reason why it wouldn't be allowed.
Edit #2: From a comment #ErenErsonmez made:
However, as long as the extension method doesn't have the same signature as an instance method, I don't understand how it could ever cause ambiguity with a static method
If you change the signature of the extension method it will definitely work. So the following will work:
class A
{
public static void Foo() { }
}
static class Ext
{
public static void Foo(this A me, int i)
{ }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Foo(10);
Console.ReadLine();
}
}
So it looks more like the issue is an ambiguity one and not that there can't ever be an extension method of the same name as a method that already exists.
The problem is overload resolution: The static method Foo() is a candidate, it is applicable - just choosing it as best match will cause an error - which is exactly what happens. Extension methods are only candidates for overload resolution after all other candidates have been considered. In the case of OPs problem case the extension method will not even have been considered before the error occurs.
It appears from this MSDN article that this is due to security concerns.
I have often heard the concern that extension methods can be used to
hijack or subvert the intended behavior of existing methods. Visual
Basic addresses this by ensuring that, wherever possible, an instance
method is preferable over an extension method.
The language allows extension methods to be used to create overloads
for existing instance methods with different signatures. This allows
extension methods to be used to create overloads, while preventing the
existing instance method from being overridden. If an extension method
exists with the same signature as an instance method, the shadowing
rules that are built into the compiler will prefer the instance
method, therefore eliminating the possibility of an extension method
overriding existing base class instance functionality
This is VB focused (and instance focused), but still, the general idea is there. Basically, the extension method takes the lowest precedence so that methods cannot be hijacked, and since the class already has a method signature for what you are trying to do, that takes precedence and throws the standard extension method error (when trying to call from an instance object). You can never have two methods with the same signature, and that is what you are asking to be attempted here essentially...and allowing it would be a security concern as explained above already.
Then, add the confusion that will be created by this, and it is just a bad idea to allow it.

Why can you not invoke extension methods directly?

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.

Categories

Resources