【发布时间】:2014-10-13 08:20:34
【问题描述】:
我有类和接口:
public class TestClass : ITestInterface
{
public int GetStatus()
{
return -1;
}
}
public interface ITestInterface
{
int GetStatus();
}
我想动态创建 TestClass 的子类,如下所示:
public class TestClass2 : TestClass
{
public new int GetStatus()
{
return base.GetStatus();
}
}
我有一些代码可以创建子类并覆盖所有虚拟方法,但是当方法是虚拟最终(GetStatus)时,我得到:
"Declaration referenced in a method implementation cannot be a final method."
有什么想法可以做到吗?
PS:如果您愿意,我可以发布提到的代码。
编辑 1:
'一些代码':
public static T GetSubClass<T>() where T : class
{
var builder = DefineType<T>();
DefineOverrideMethods(builder, typeof(T));
var type = CreateType(builder);
return (T)Activator.CreateInstance(type);
}
private static TypeBuilder DefineType<T>() where T : class
{
return _moduleBuilder.DefineType("Proxy_" + typeof (T).Name,
TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public, typeof (T));
}
private static void DefineOverrideMethods(TypeBuilder builder, Type type)
{
foreach (var virtualMethodInfo in GetVirtualMethods(type))
{
var parameters = GetMethodParametersTypes(virtualMethodInfo);
var newMethodInfo = DefineNewVirtualMethod(builder, virtualMethodInfo, parameters);
var il = newMethodInfo.GetILGenerator();
var local = EmitCreateLocal(il, newMethodInfo);
EmitCallBaseMethod(il, virtualMethodInfo);
EmitSaveReturnToLocal(il, local);
EmitReturnMethod(il, virtualMethodInfo, local);
builder.DefineMethodOverride(newMethodInfo, virtualMethodInfo);
}
}
private static IEnumerable<MethodInfo> GetVirtualMethods(Type type)
{
return type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(q => q.IsVirtual);
}
private static Type[] GetMethodParametersTypes(MethodInfo virtualMethodInfo)
{
return virtualMethodInfo.GetParameters().Select(q => q.ParameterType).ToArray();
}
private static MethodBuilder DefineNewVirtualMethod(TypeBuilder builder, MethodInfo virtualMethodInfo, Type[] parameters)
{
return builder.DefineMethod(virtualMethodInfo.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
virtualMethodInfo.ReturnType, parameters);
}
private static void EmitSaveReturnToLocal(ILGenerator il, LocalBuilder local)
{
il.Emit(OpCodes.Stloc_S, local);
il.Emit(OpCodes.Ldloc_S, local);
}
private static LocalBuilder EmitCreateLocal(ILGenerator il, MethodBuilder newMethodInfo)
{
return il.DeclareLocal(newMethodInfo.ReturnType);
}
private static Type CreateType(TypeBuilder builder)
{
builder.DefineDefaultConstructor(MethodAttributes.Public);
var type = builder.CreateType();
return type;
}
private static void EmitReturnMethod(ILGenerator il, MethodInfo methodInfo, LocalBuilder local)
{
il.Emit(OpCodes.Ldloc_S, local);
il.Emit(OpCodes.Ret);
}
private static void EmitCallBaseMethod(ILGenerator il, MethodInfo virtualMethodInfo)
{
ushort index = 0;
while (index < virtualMethodInfo.GetParameters().Length + 1)
il.Emit(OpCodes.Ldarg, index++);
il.Emit(OpCodes.Call, virtualMethodInfo);
}
var type = builder.CreateType(); 抛出异常
编辑 2: @拉胡尔: 语言是 C#,正如您在方法“GetVirtualMethods”中看到的,有属性“IsVirtual”。 属性 'IsFinal' 也存在那里,并为 'GetStatus' 方法返回 true。
编辑 3: @Wim.van.Gool: 是的,你是对的 - 我不能覆盖非虚拟方法。我在这里尝试做的是使用调用基本方法的虚拟实现来隐藏“GetStatus”的基本实现。 为什么会有用?想象一下,方法 'GetSubClass' 会返回一个行为类似于基础的类,但例如在基础实现调用之前和之后添加了日志方法。
@Michał 科莫罗夫斯基: 谢谢你的答案。它有效,但只是部分有效。程序不再抛出错误,但在此示例中:
ITestInterface obj = StaticClass.GetSubClass<TestClass>();
obj.GetStatus();
'GetStatus' 方法直接从基类 (TestClass) 调用,而不是从动态创建的子类调用。
我尝试添加:builder.AddInterfaceImplementation(typeof(ITestInterface));,但没有任何区别。
编辑 4:
@danish:谢谢你的回答。它现在正在工作。 NewSlot 保存问题。
实际上整个属性数据:MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual。
谢谢你们的帮助。不幸的是,我无法将两个答案都标记为正确答案,但两者对于解决问题都很重要。
【问题讨论】:
-
欢迎来到 SO。我们需要看到“一些代码”——你到底在哪里得到了那个错误。
-
final?你说的是 C# 还是其他语言? -
我可能弄错了您在此处尝试执行的操作,但您不能覆盖非虚拟方法。 'new' 关键字提供了一种声明类成员的方法,其语法与基类成员完全相同,但这与覆盖它不同。因此,对于非虚拟(最终/密封)的方法,您必须生成非虚拟成员。话虽如此,让子类的非虚拟成员只调用他们的基本亲属有什么意义?
标签: c# class reflection methods overriding