You can load a token to get RuntimeTypeHandle
and then call Type.GetTypeFromHandle
.
After playing around with this newobj <ctor>
through the same security exception as above. However, I was successful using Activator.CreateInstance
Here's working MSIL (note there is a type check first (addressing the original question) and then an example of how to work and create and return the private struct ListBuilder<T>
:
.method public static object IsRuntimeType(class [mscorlib]System.Type 'type') cil managed
{
// Code size 48 (0x30)
.maxstack 5
IL_0000: ldarg.0
IL_0001: ldtoken [mscorlib]System.RuntimeType
IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000b: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
class [mscorlib]System.Type)
IL_0010: pop
IL_0011: ldtoken valuetype [mscorlib]System.RuntimeType/ListBuilder`1<string>
IL_0016: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_001b: ldc.i4.1
IL_001c: newarr [mscorlib]System.Object
IL_0021: dup
IL_0022: ldc.i4.0
IL_0023: ldc.i4.0
IL_0024: box [mscorlib]System.Int32
IL_0029: stelem.ref
IL_002a: call object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type,
object[])
IL_002f: ret
} // end of method Dyn::IsRuntimeType
Here's the CSharp used to create the dynamic DLL and test the code above, from which the MSIL above was extracted using ILDASM.exe
var asmName = new AssemblyName("MsilDyn");
AppDomain domain = AppDomain.CurrentDomain;
AssemblyBuilder wrapperAssembly =
domain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.RunAndSave);
var assemblyPath = asmName.Name + ".dll";
ModuleBuilder wrapperModule =
wrapperAssembly.DefineDynamicModule(asmName.Name,
assemblyPath);
// Define a type to contain the method.
TypeBuilder typeBuilder =
wrapperModule.DefineType("Dyn", TypeAttributes.Public);
MethodAttributes atts = MethodAttributes.Public | MethodAttributes.Static;
MethodBuilder methodBuilder =
typeBuilder.DefineMethod($"IsRuntimeType",
atts,
typeof(object),
new[] { typeof(Type) });
methodBuilder.DefineParameter(1, ParameterAttributes.None, "type");
ILGenerator il = methodBuilder.GetILGenerator();
var assem = typeof(string).Assembly;
var t = assem.GetType("System.RuntimeType");
var nestedList = t.GetMembers();
var resolveType = typeof(Type).GetMethod("GetType", new[] { typeof(string) });//., BindingFlags.Static | BindingFlags.Public);
var opEqual = typeof(Type).GetMethod("op_Equality");
var getTypeHandle = typeof(Type).GetMethod("GetTypeFromHandle");
var runtimeType = Type.GetType("System.RuntimeType");
var listBuilderType = (TypeInfo)runtimeType.GetMember("ListBuilder`1",
BindingFlags.Public | BindingFlags.NonPublic)[0];
var ListBuilderOfStringType = listBuilderType.MakeGenericType(new[] { typeof(string) });
// From C#
/*
var ctor = listBuilderType.GetConstructor(new[] { typeof(int) });
var instance = Activator.CreateInstance(ListBuilderOfStringType, new object[] { 0 });
*/
var listBuilderCtorArgs = new[] { typeof(Type), typeof(object[]) };
var ctor = typeof(Activator).GetMethod("CreateInstance", listBuilderCtorArgs);
// Generate an MSIL example of working with the RuntimeType for comparison
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldtoken, runtimeType);
il.Emit(OpCodes.Call, getTypeHandle);
il.Emit(OpCodes.Call, opEqual);
il.Emit(OpCodes.Pop);
// Generate an MSIL of creating RuntimeType.ListBuilder<string>
il.Emit(OpCodes.Ldtoken, ListBuilderOfStringType);
il.Emit(OpCodes.Call, getTypeHandle);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Box, typeof(int));
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Call, ctor);
il.Emit(OpCodes.Ret);
var result = typeBuilder.CreateType();
wrapperAssembly.Save(assemblyPath);
var method = result.GetMethod("IsRuntimeType", BindingFlags.Public | BindingFlags.Static);
var stringType = typeof(string);
var listBuilderOfStringInstance = method.Invoke(null, new[] { stringType });
GetMethods
andGetFields
and so on based on the reflection of .NET. This calling requiresSystem.RuntimeType.ListBuilder'1<T>.ToArray
and some other non-public stuff. I just want to know how to do this with pure IL code. Sure I can use dynamic methods or something (that's what i'm doing right now and I'm not happy with it), but that's missing the entire point. I'm doing it for myself, to learn and to have fun. – Squashy