Skip to content

Instantly share code, notes, and snippets.

@GeeLaw
Created December 22, 2025 08:57
Show Gist options
  • Select an option

  • Save GeeLaw/5626c0c3c3b1af9ddc9c4d4796ecf317 to your computer and use it in GitHub Desktop.

Select an option

Save GeeLaw/5626c0c3c3b1af9ddc9c4d4796ecf317 to your computer and use it in GitHub Desktop.
Private constructor does not prevent derivation at IL level.
// 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