我需要在通用抽象类上创建一个扩展方法,但是只暴露基本的非泛型抽象类。永远不会有一个直接从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();
以上结果是编译时错误:
'Abstract'不包含'Extension'的定义,并且没有扩展方法'Extension'接受类型'Abstract'的第一个参数可以找到
我认为在Abstract
上添加了扩展名,但这不允许我转换为更具体的扩展名:
public static void Extension(this Abstract a)
{
Console.WriteLine("Base");
Abstract<?> cast = MagiclyCastToGeneric(a);
Extensions.Extension(cast);
}
答案 0 :(得分:1)
一种方法是使用dynamic
:
public static void Extension(this Abstract a)
{
Console.WriteLine("Base");
dynamic d = a;
Extensions.Extension(d);
}
这导致重载决策在运行时而不是编译时完成 - DLR将选择要选择的最具体的重载版本,即Extension(this Abstract<T>)
。
请注意,如果有一个具体类型直接继承Abstract
,那么上面会导致StackOverflowException
。
答案 1 :(得分:0)
如果你不能像在dav_i的答案中那样使用DLR / dynamic(即你在.Net2.0上),你可以手动以类似的方式做到这一点。伪代码:
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, ....);
}