Created
December 22, 2025 08:57
-
-
Save GeeLaw/5626c0c3c3b1af9ddc9c4d4796ecf317 to your computer and use it in GitHub Desktop.
Private constructor does not prevent derivation at IL level.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // MIT license. | |
| using System; | |
| using System.Reflection; | |
| using System.Reflection.Emit; | |
| public class Base { private Base() { } } | |
| class Program | |
| { | |
| static void EnsureBaseCtorNotAccessible(string asmname, string modname) | |
| { | |
| try | |
| { | |
| var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(asmname), AssemblyBuilderAccess.Run); | |
| var mb = ab.DefineDynamicModule(modname); | |
| var tb = mb.DefineType("Derived", TypeAttributes.Public, typeof(Base)); | |
| var cb = tb.DefineDefaultConstructor(MethodAttributes.Public); | |
| var t = tb.CreateType(); | |
| Activator.CreateInstance(t); | |
| } | |
| catch (Exception ex) | |
| { | |
| Console.WriteLine(ex); | |
| } | |
| Console.WriteLine(); | |
| } | |
| static void EnsureBaseCtorNotNeeded(string asmname, string modname) | |
| { | |
| var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(asmname), AssemblyBuilderAccess.Run); | |
| var mb = ab.DefineDynamicModule(modname); | |
| var tb = mb.DefineType("Derived", TypeAttributes.Public, typeof(Base)); | |
| var cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]); | |
| var il = cb.GetILGenerator(); | |
| il.Emit(OpCodes.Ret); | |
| var t = tb.CreateType(); | |
| var obj = Activator.CreateInstance(t); | |
| Console.WriteLine("Constructed " + obj); | |
| Console.WriteLine("Base type is " + obj.GetType().BaseType); | |
| Console.WriteLine("(obj is Base) == " + (obj is Base)); | |
| } | |
| static void Main() | |
| { | |
| EnsureBaseCtorNotAccessible("test1", "test1mod"); | |
| EnsureBaseCtorNotNeeded("test2", "test2mod"); | |
| } | |
| } | |
| /* Output: | |
| System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. | |
| ---> System.MethodAccessException: Attempt by method 'Derived..ctor()' to access method 'Base..ctor()' failed. | |
| at Derived..ctor() | |
| at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions) | |
| --- End of inner exception stack trace --- | |
| at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions) | |
| at Program.EnsureBaseCtorNotAccessible(String asmname, String modname) in [path redacted] | |
| Constructed Derived | |
| Base type is Base | |
| (obj is Base) == True | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment