{"record":{"id":"50c03f7587676bc9","repo":"pardeike/Harmony","slug":"the-type-0-must-declare-an-empty-constructor-the-constructor","errorCode":null,"errorMessage":"The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).","messagePattern":"The type (.+?) must declare an empty constructor \\(the constructor may be private, internal, protected, protected internal, or public\\)\\.","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"Harmony/Extras/FastAccess.cs","lineNumber":52,"sourceCode":"\t/// <returns>An delegate</returns>\r\n\t///\r\n\tpublic delegate T InstantiationHandler<out T>();\r\n\r\n\t/// <summary>A helper class for fast access to getters and setters</summary>\r\n\tpublic static class FastAccess\r\n\t{\r\n\t\t/// <summary>Creates an instantiation delegate</summary>\r\n\t\t/// <typeparam name=\"T\">Type that constructor creates</typeparam>\r\n\t\t/// <returns>The new instantiation delegate</returns>\r\n\t\t///\r\n\t\tpublic static InstantiationHandler<T> CreateInstantiationHandler<T>()\r\n\t\t{\r\n\t\t\tvar constructorInfo =\r\n\t\t\t\ttypeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null,\r\n\t\t\t\t\t[], null);\r\n\t\t\tif (constructorInfo is null)\r\n\t\t\t{\r\n\t\t\t\tthrow new ApplicationException(string.Format(\r\n\t\t\t\t\t\"The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).\",\r\n\t\t\t\t\ttypeof(T)));\r\n\t\t\t}\r\n\r\n\t\t\tvar dynamicMethod = new DynamicMethodDefinition($\"InstantiateObject_{typeof(T).Name}\", typeof(T), null);\r\n\t\t\tvar generator = dynamicMethod.GetILGenerator();\r\n\t\t\tgenerator.Emit(OpCodes.Newobj, constructorInfo);\r\n\t\t\tgenerator.Emit(OpCodes.Ret);\r\n\t\t\treturn dynamicMethod.Generate().CreateDelegate<InstantiationHandler<T>>();\r\n\t\t}\r\n\r\n\t\t/// <summary>Creates an getter delegate for a property</summary>\r\n\t\t/// <typeparam name=\"T\">Type that getter reads property from</typeparam>\r\n\t\t/// <typeparam name=\"S\">Type of the property that gets accessed</typeparam>\r\n\t\t/// <param name=\"propertyInfo\">The property</param>\r\n\t\t/// <returns>The new getter delegate</returns>\r\n\t\t///\r\n\t\t[Obsolete(\"Use AccessTools.MethodDelegate<Func<T, S>>(PropertyInfo.GetGetMethod(true))\")]\r","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Extras/FastAccess.cs#L34-L70","documentation":"FastAccess.CreateInstantiationHandler builds a compiled delegate that calls T's parameterless constructor via IL. Harmony looks up a zero-argument constructor (any visibility) with reflection; if the type declares none, no instantiation delegate can be emitted and this ApplicationException is thrown.","triggerScenarios":"Calling CreateInstantiationHandler<T>() (or APIs that use it, e.g. accessing patch/unpatch shared state via AccessTools-created instances) where typeof(T) has no empty constructor — including structs with fields-only, classes with only parameterized constructors, or anonymous types with required args.","commonSituations":"Using Harmony's AccessTools/FastAccess helpers on a class after adding a constructor with parameters; types defined with required members or primary constructors without a default; plugin authors instantiating config/option classes that only define (string, int) style constructors.","solutions":["Add a parameterless constructor to type T (any accessibility: private, internal, protected, protected internal, or public)","If you cannot modify T, create a dedicated adapter/handler type with an empty constructor","Point the instantiation handler at a different type that has a default constructor","Use Activator.CreateInstance with explicit constructor arguments instead of the fast instantiation handler"],"exampleFix":"// before\nclass Config { public Config(string name) { Name = name; } }\nvar h = FastAccess.CreateInstantiationHandler<Config>();\n// after\nclass Config { public Config() { } public Config(string name) { Name = name; } }\nvar h = FastAccess.CreateInstantiationHandler<Config>();","handlingStrategy":"validation","validationCode":"var hasDefaultCtor = typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) is not null;\nif (!hasDefaultCtor) throw new InvalidOperationException($\"{typeof(T)} needs a parameterless constructor before CreateInstantiationHandler<T>()\");","typeGuard":"static bool HasEmptyConstructor<T>() => typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) is not null;","tryCatchPattern":null,"preventionTips":["Always give types used with FastAccess/AccessTools instantiation a parameterless constructor","Check types with a reflection guard before passing them to instantiation helpers","Watch out for primary constructors / required members which remove the implicit default constructor","Write a unit test that walks the types you instantiate and asserts each has an empty constructor"],"tags":["reflection","il","constructor","harmony"],"backgroundTag":"missing-default-constructor","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}