如果这是您真的想要做的,那么是的,是可以使用反射发射覆盖另一个程序集中的内部方法。
如果您阅读CLI specification (ECMA-335)(特别是第 II.10.3.3 节“可访问性和覆盖”),您会发现:
[注意:即使派生类可能无法访问方法,也可以重写该方法。
如果方法具有程序集可访问性,则如果它被不同程序集中的方法覆盖,则它应具有公共可访问性。类似的规则适用于 famandassem,其中 famorassem 也允许在大会之外。在这两种情况下,程序集或 famandassem 可以分别在同一个程序集中使用。尾注]
(这里,assembly、famandassem 和 famorassem 分别对应于 C# internal、protected private 和 protected internal。)
但有一个问题。在同一部分,您还会发现:
如果指定了严格标志 (§II.23.1.10),则只能覆盖可访问的虚拟方法。
C# 编译器在所有非公共虚拟方法上设置此标志。因此,即使使用反射发射,您也不能从 C# 编译的程序集中扩展类并覆盖在该程序集中声明的内部方法,除非您能够从该方法中删除严格标志(可能使用二进制编辑器,并且如果程序集是强命名然后这将使签名无效)。但是您可以创建两个带有反射发射的程序集,在第一个程序集中定义一个具有虚拟内部方法的基类,然后在第二个程序集中扩展该类并覆盖该方法,这可以用这个来演示代码:
using System;
using System.Reflection;
using System.Reflection.Emit;
public interface IBase {
void X();
}
class Program {
public static void Main() {
ILGenerator ilGenerator;
var assembly1 = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName("EmittedAssembly1"),
AssemblyBuilderAccess.Run
);
var module1 = assembly1.DefineDynamicModule("EmittedModule1");
// Define the base class.
var typeBuilderBase = module1.DefineType("Base", TypeAttributes.Public);
typeBuilderBase.DefineDefaultConstructor(MethodAttributes.Public);
typeBuilderBase.AddInterfaceImplementation(typeof(IBase));
// This is the internal method that will be overridden.
var methodBuilderBaseX = typeBuilderBase.DefineMethod(
"X",
MethodAttributes.Assembly | MethodAttributes.Virtual | MethodAttributes.NewSlot,
typeof(void),
Array.Empty<Type>()
);
ilGenerator = methodBuilderBaseX.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldstr, "X from Base");
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}));
ilGenerator.Emit(OpCodes.Ret);
// Define an explicit interface implementation that will be used to call
// Base.X() from the created instance of Derived.
var methodBuilderBaseInterfaceX = typeBuilderBase.DefineMethod(
"IBase.X",
MethodAttributes.Private | MethodAttributes.Virtual,
typeof(void),
Array.Empty<Type>()
);
ilGenerator = methodBuilderBaseInterfaceX.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Callvirt, methodBuilderBaseX);
ilGenerator.Emit(OpCodes.Ret);
typeBuilderBase.DefineMethodOverride(methodBuilderBaseInterfaceX, typeof(IBase).GetMethod("X"));
typeBuilderBase.CreateType();
// This is the assembly in which the internal method will be overridden.
var assembly2 = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName("EmittedAssembly2"),
AssemblyBuilderAccess.Run
);
var module2 = assembly2.DefineDynamicModule("EmittedModule2");
var typeBuilderDerived = module2.DefineType("Derived", TypeAttributes.Public);
typeBuilderDerived.SetParent(typeBuilderBase);
typeBuilderDerived.DefineDefaultConstructor(MethodAttributes.Public);
// Override the internal method in Base. Note that the accessibility of the overridden
// method must be public.
var methodBuilderDerivedX = typeBuilderDerived.DefineMethod(
"X",
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(void),
Array.Empty<Type>()
);
ilGenerator = methodBuilderDerivedX.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldstr, "X from Derived");
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}));
ilGenerator.Emit(OpCodes.Ret);
var typeDerived = typeBuilderDerived.CreateType();
// Create an instance of the emitted Derived type.
var instance = (IBase)typeDerived.GetConstructor(Array.Empty<Type>()).Invoke(Array.Empty<object>());
// Call the overridden method. This outputs "X from Derived"!
instance.X();
}
}
如果您将MethodAttributes.CheckAccessOnOverride(即strict 标志)添加到Base 中X 的定义中,您将收到此错误(与尝试执行此操作时遇到的相同)使用 C# 编译类型):
未处理的异常。 System.TypeLoadException:来自程序集“EmittedAssembly2,Version=0.0.0.0,Culture=neutral,PublicKeyToken=null”的类型“Derived”的方法“X”正在覆盖从该程序集中不可见的方法。