/// <summary>
        /// Get the managed size of a given type. This matches an IL-level sizeof(t), even if it cannot be determined normally in C#.
        /// Note that sizeof(t) != Marshal.SizeOf(t), f.e. when t is char.
        /// </summary>
        /// <param name="t">The type to get the size from.</param>
        /// <returns>The managed type size.</returns>
        public static int GetManagedSize(this Type t) {
            if (_GetManagedSizeCache.TryGetValue(t, out int size))
                return size;

            if (_GetManagedSizeHelper == null) {
                Assembly asm;

                const string @namespace = "MonoMod.Utils";
                const string @name = "GetManagedSizeHelper";
                const string @fullName = @namespace + "." + @name;

#if !CECIL0_9
                using (
#endif
                ModuleDefinition module = ModuleDefinition.CreateModule(
                    @fullName,
                    new ModuleParameters() {
                        Kind = ModuleKind.Dll,
#if !CECIL0_9 && MONOMOD_UTILS
                        ReflectionImporterProvider = MMReflectionImporter.Provider
#endif
                    }
                )
#if CECIL0_9
                ;
#else
                )
#endif
                {

                    TypeDefinition type = new TypeDefinition(
                        @namespace,
                        @name,
                        MC.TypeAttributes.Public | MC.TypeAttributes.Abstract | MC.TypeAttributes.Sealed
                    ) {
                        BaseType = module.TypeSystem.Object
                    };
                    module.Types.Add(type);

                    MethodDefinition method = new MethodDefinition(@name,
                        MC.MethodAttributes.Public | MC.MethodAttributes.Static | MC.MethodAttributes.HideBySig,
                        module.TypeSystem.Int32
                    );
                    GenericParameter genParam = new GenericParameter("T", method);
                    method.GenericParameters.Add(genParam);
                    type.Methods.Add(method);

                    ILProcessor il = method.Body.GetILProcessor();
                    il.Emit(OpCodes.Sizeof, genParam);
                    il.Emit(OpCodes.Ret);

                    asm = ReflectionHelper.Load(module);
                }

                _GetManagedSizeHelper = asm.GetType(@fullName).GetMethod(@name);
            }

            size =  (_GetManagedSizeHelper.MakeGenericMethod(t).CreateDelegate<Func<int>>() as Func<int>)();
            lock (_GetManagedSizeCache) {
                return _GetManagedSizeCache[t] = size;
            }
        }
        public MethodInfo Generate(object context)
        {
            string typeName = Environment.GetEnvironmentVariable("MONOMOD_DMD_TYPE");

            switch (typeName?.ToLowerInvariant())
            {
            case "dynamicmethod":
            case "dm":
                return(DMDEmitDynamicMethodGenerator.Generate(this, context));

#if !NETSTANDARD
            case "methodbuilder":
            case "mb":
                return(DMDEmitMethodBuilderGenerator.Generate(this, context));
#endif

            case "cecil":
            case "md":
                return(DMDCecilGenerator.Generate(this, context));

            default:
                Type type = ReflectionHelper.GetType(typeName);
                if (type != null)
                {
                    if (!t__IDMDGenerator.IsCompatible(type))
                    {
                        throw new ArgumentException($"Invalid DMDGenerator type: {typeName}");
                    }
                    if (!_DMDGeneratorCache.TryGetValue(typeName, out _IDMDGenerator gen))
                    {
                        _DMDGeneratorCache[typeName] = gen = Activator.CreateInstance(type) as _IDMDGenerator;
                    }
                    return(gen.Generate(this, context));
                }

                if (_PreferCecil)
                {
                    return(DMDCecilGenerator.Generate(this, context));
                }

                if (Debug)
#if NETSTANDARD
                { return(DMDCecilGenerator.Generate(this, context)); }
#else
                { return(DMDEmitMethodBuilderGenerator.Generate(this, context)); }
#endif

                // In .NET Framework, DynamicILGenerator doesn't support fault and filter blocks.
                // This is a non-issue in .NET Core, yet it could still be an issue in mono.
                // https://github.com/dotnet/coreclr/issues/1764
#if NETFRAMEWORK
                if (Definition.Body.ExceptionHandlers.Any(eh =>
                                                          eh.HandlerType == ExceptionHandlerType.Fault ||
                                                          eh.HandlerType == ExceptionHandlerType.Filter
                                                          ))
#if NETSTANDARD
                { return(DMDCecilGenerator.Generate(this, context)); }
#else
                { return(DMDEmitMethodBuilderGenerator.Generate(this, context)); }
#endif
#endif

                return(DMDEmitDynamicMethodGenerator.Generate(this, context));
            }
        }