在运行时创建一个简单的类【难度:5级】:
答案1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
public static class Kata
{
public static bool DefineClass(string className, Dictionary<string, Type> properties, ref Type actualType)
{
actualType = MyTypeBuilder.CompileResultType(className, properties);
return actualType != null;
}
}
public static class MyTypeBuilder
{
private const string _AssemblyName = "RuntimeAssembly";
private const string _ModuleName = "MainModule";
private static Lazy<ModuleBuilder> moduleBuilder = new Lazy<ModuleBuilder>(() =>
{
var an = new AssemblyName(_AssemblyName);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
return assemblyBuilder.DefineDynamicModule(_ModuleName);
});
public static Type CompileResultType(string className, Dictionary<string, Type> props)
{
Assembly dynamicAssembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.FullName.StartsWith(_AssemblyName + ","));
Type existingType = (dynamicAssembly == null) ? null : dynamicAssembly.GetType(className);
if (existingType != null) return null;
TypeBuilder tb = GetTypeBuilder(className);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
foreach (var field in props)
CreateProperty(tb, field.Key, field.Value);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder(string className)
{
TypeBuilder tb = moduleBuilder.Value.DefineType(className,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] {
propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
答案2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
public static class Kata
{
private static AssemblyBuilder AssemblyBuilder {
get; set; }
private static ModuleBuilder ModuleBuilder {
get; set; }
private static AssemblyName AName {
get; set; }
private static void CreateProp(String pName, Type type, TypeBuilder typeBuilder)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + pName, type, FieldAttributes.Private);
PropertyBuilder pBuilder = typeBuilder.DefineProperty(pName, PropertyAttributes.HasDefault, type, null);
MethodBuilder getMethBuilder = typeBuilder.DefineMethod("get_" + pName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
type, null);
ILGenerator iLGen = getMethBuilder.GetILGenerator();
iLGen.Emit(OpCodes.Ldarg_0);
iLGen.Emit(OpCodes.Ldfld, fieldBuilder);
iLGen.Emit(OpCodes.Ret);
MethodBuilder setMethBuilder = typeBuilder.DefineMethod("set_" + pName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null, new Type[1] {
type });
iLGen = setMethBuilder.GetILGenerator();
iLGen.Emit(OpCodes.Ldarg_0);
iLGen.Emit(OpCodes.Ldarg_1);
iLGen.Emit(OpCodes.Stfld, fieldBuilder);
iLGen.Emit(OpCodes.Ret);
pBuilder.SetGetMethod(getMethBuilder);
pBuilder.SetSetMethod(setMethBuilder);
}
public static bool DefineClass(String className, Dictionary<String, Type> properties, ref Type actualType)
{
if (AName == null && AssemblyBuilder == null && ModuleBuilder == null)
{
AName = new AssemblyName("RuntimeAssembly");
AName.Version = new Version(1, 0, 0, 0);
AName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture;
AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(AName, AssemblyBuilderAccess.Run);
ModuleBuilder = Assembly