I need to create an extension method on a generic abstract class, but where only the base, non-generic abstract class is ever exposed. There will never be a concrete class which inherits directly from Abstract
.
public abstract class Abstract { }
public abstract class Abstract<T> : Abstract { }
public class Concrete : Abstract<string> { }
public static Abstract GetConcrete()
{
return new Concrete();
}
public static class Extensions
{
public static void Extension<T>(this Abstract<T> a)
{
Console.WriteLine("Generic");
}
}
Abstract a = GetConcrete();
a.Extension();
The above results in a compile-time error:
'Abstract' does not contain a definition for 'Extension' and no extension method 'Extension' accepting a first argument of type 'Abstract' could be found
I thought that adding an extension on Abstract
but this doesn't allow me to cast to the more specific extension:
public static void Extension(this Abstract a)
{
Console.WriteLine("Base");
Abstract<?> cast = MagiclyCastToGeneric(a);
Extensions.Extension(cast);
}
One way is to use the "magic" of dynamic
:
public static void Extension(this Abstract a)
{
Console.WriteLine("Base");
dynamic d = a;
Extensions.Extension(d);
}
This causes the overload resolution to be done at run-time rather than compile-time - the DLR will choose the most specific version of the overload to be chosen, which is Extension(this Abstract<T>)
.
Beware, if there were to be a concrete type directly inheriting Abstract
then the above would cause a StackOverflowException
.
In case you can't use DLR/dynamic as in dav_i's answer (ie you're on .Net2.0), you can do that in a similar way, manually. Pseudocode:
public static void Extension(this Abstract a)
{
var actualType = a.GetType();
var interestingBaseType = ...search basetypes of actualType for Abstract<T>
var theTypeParameter = interestingBaseType.GetGenericArguments()[0];
var genericMethodDef = typeof(Extensions).GetMethod("Extension");
var concreteMethod = genericMethodDef.MakeGenericMethod(theTypeParameter);
concreteMethod.Invoke(a, ....);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.