If this is what you really want to do, then yes, it is possible to override an internal method in another assembly using reflection emit.
If you read the CLI specification (ECMA-335) (in particular, section II.10.3.3, "Accessibility and overriding"), you will find this:
[Note: A method can be overridden even if it might not be accessed by the derived class.
If a method has assembly accessibility, then it shall have public accessibility if it is being overridden by a method in a different assembly. A similar rule applies to famandassem, where also famorassem is allowed outside the assembly. In both cases assembly or famandassem, respectively, can be used inside the same assembly. end note]
(Here, assembly
, famandassem
and famorassem
correspond to C# internal
, protected private
and protected internal
, respectively.)
But there is a catch. In the same section, you will also find:
If the strict flag (§II.23.1.10) is specified then only accessible virtual methods can be overridden.
The C# compiler sets this flag on all non-public virtual methods. So you cannot extend a class from a C# compiled assembly and override an internal method declared in that assembly, even with reflection emit, unless you are able to remove the strict flag from that method (perhaps using a binary editor, and if the assembly is strong named then this will invalidate the signature). But you can create two assemblies with reflection emit, define a base class with a virtual internal method in the first one, and extend the class and override the method in the second assembly, which can be demonstrated with this code:
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();
}
}
If you add MethodAttributes.CheckAccessOnOverride
(which is the strict
flag) to the definition of X
in Base
, you will get this error (which is the same as what you would get when attempting to do this with a C# compiled type):
Unhandled exception. System.TypeLoadException: Method 'X' on type 'Derived' from assembly 'EmittedAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is overriding a method that is not visible from that assembly.