I'm trying to create this C# class by using System.Reflection.Emit.
private class MyTestData : IMyClonable
{
private int _testValue = 0;
public int testValue
{
get { return _testValue; }
set { _testValue = value; }
}
public IMyClonable Clone()
{
MyTestData clone = new MyTestData();
clone._testValue = _testValue;
return clone ;
}
}
This class must be created from this interface:
public interface IMyTestData : IMyClonable
{
int testValue { get; set; }
}
I already made the code that generate properties and this work's fine. But I stuck when I'm trying to create method Clone(). I don't know how to create an instance of this class itself and save it in a local variable.
Here is the code to generate method Clone():
private static void MakeCloneMethod(Type componentType, TypeBuilder typeBuilder)
{
ConstructorBuilder ctor =
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
MethodInfo cloneMethod = typeof(IMyClonable).GetMethod("Clone");
MethodAttributes methodIlAttributes =
(cloneMethod.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Final;
MethodBuilder cloneMthdBldr = typeBuilder.DefineMethod(
"Clone", methodIlAttributes, typeof(IMyClonable), new Type[] { });
ILGenerator ilgen = cloneMthdBldr.GetILGenerator();
LocalBuilder returnValue = ilgen.DeclareLocal(typeBuilder.AsType());
ilgen.Emit(OpCodes.Newobj, ctor);
ilgen.Emit(OpCodes.Stloc_S, returnValue);
CloneProperties(componentType, ilgen);
ilgen.Emit(OpCodes.Ldloc_S);
ilgen.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(cloneMthdBldr, cloneMethod);
}
private static void CloneProperties(Type componentType, ILGenerator ilgen)
{
PropertyInfo[] allProperties = GetPublicProperties(componentType);
foreach (PropertyInfo propInfo in allProperties)
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, builders[propInfo]);
ilgen.Emit(OpCodes.Stfld, builders[propInfo]);
ilgen.Emit(OpCodes.Ldloc_0);
}
}
I get the System.InvalidProgramException when I try to call Clone() method. Even if I comment call of method CloneProperties(). What I'm doing wrong?
I got it! Here is working code:
private static void MakeCloneMethod(Type componentType, TypeBuilder typeBuilder)
{
Type thisType = typeBuilder.AsType();
Type itype = typeof(IMyClonable);
MethodInfo cloneMthd = itype.GetMethod("Clone");
MethodBuilder cloneMthdBldr = typeBuilder.DefineMethod(
cloneMthd.Name, cloneMthd.Attributes & ~MethodAttributes.Abstract,
itype, new Type[] {});
typeBuilder.DefineMethodOverride(cloneMthdBldr, cloneMthd);
ILGenerator gen = cloneMthdBldr.GetILGenerator();
LocalBuilder returnValue = gen.DeclareLocal(thisType);
gen.Emit(OpCodes.Newobj, typeBuilder.DefineDefaultConstructor(MethodAttributes.Public));
gen.Emit(OpCodes.Stloc_S, returnValue);
PropertyInfo[] allProperties = GetPublicProperties(componentType);
foreach (PropertyInfo propInfo in allProperties)
{
gen.Emit(OpCodes.Ldloc_S, returnValue);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, builders[propInfo]);
gen.Emit(OpCodes.Stfld, builders[propInfo]);
}
gen.Emit(OpCodes.Ldloc_S, returnValue);
gen.Emit(OpCodes.Ret);
}
Thanks to Svick!
Related
So I have a class:
public class MyClass : IMyClass
{
public string foo {get;}
public MyClass bar {get;}
}
And an interface:
public interface IMyClass
{
string foo {get;}
}
And a system to create an emitted type:
private static Type MakeDynamicType<T>() where T : class
{
var myType = GetTypeBuilder();
myType.AddInterfaceImplementation(typeof(T));
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
AddProperty(myType, property, typeof(T));
AddCtor(myType, typeof(T));
return myType.CreateType();
}
private static void AddCtor(TypeBuilder myType, Type inputParamType)
{
var myCtor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
var ilGenerator = myCtor.GetILGenerator();
ilGenerator.Emit(OpCodes.Ret);
}
private const MethodAttributes GET_SET_ATTR = MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig | MethodAttributes.Virtual;
private static void AddProperty(TypeBuilder myType, PropertyInfo property, Type interfaceType)
{
var myField = myType.DefineField($"m_{property.Name}", property.PropertyType, FieldAttributes.Private);
var myProperty = myType.DefineProperty(property.Name, PropertyAttributes.HasDefault, property.PropertyType,
parameterTypes: null);
var interfaceGetMethod = interfaceType.GetMethod($"get_{property.Name}");
if (interfaceGetMethod != null)
AddGetter(myType, property, myField, myProperty, interfaceGetMethod);
var interfaceSetMethod = interfaceType.GetMethod($"set_{property.Name}");
if (interfaceSetMethod != null)
AddSetter(myType, property, myField, myProperty, interfaceSetMethod);
}
private static void AddGetter(TypeBuilder myType, PropertyInfo property, FieldInfo myField,
PropertyBuilder myProperty, MethodInfo interfaceGetMethod)
{
var myGet = myType.DefineMethod($"get_{property.Name}", GET_SET_ATTR, property.PropertyType,
Type.EmptyTypes);
var getIl = myGet.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, myField);
getIl.Emit(OpCodes.Ret);
myProperty.SetGetMethod(myGet);
myType.DefineMethodOverride(myGet, interfaceGetMethod);
}
private static void AddSetter(TypeBuilder myType, PropertyInfo property, FieldInfo myField,
PropertyBuilder myProperty, MethodInfo interfaceSetMethod)
{
var mySet = myType.DefineMethod($"set_{property.Name}", GET_SET_ATTR, returnType: null,
new[] { property.PropertyType });
var setIl = mySet.GetILGenerator();
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, myField);
setIl.Emit(OpCodes.Ret);
myProperty.SetSetMethod(mySet);
myType.DefineMethodOverride(mySet, interfaceSetMethod);
}
private static TypeBuilder GetTypeBuilder()
{
var myDomain = Thread.GetDomain();
var myAsmName = new AssemblyName("MyDynamicAssembly");
var myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
var myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");
return myModBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
}
So now how do I create an instance of my reflected type from an IMyClass type reference to a MyClass object?
public static IEnumerable<T> ToInterfacedObjects<T>(this IEnumerable<T> data) where T : class
{
var myType = MakeDynamicType<T>();
var list = new List<T>();
foreach (var datum in data)
{
list.Add((T)myType.GetValue(datum));//What do I write for GetValue??
}
return list;
}
My goal is to start with an IMyClass which has an underlying type of MyClass, which has both foo and bar, and end with an IMyClass which has an underlying type of an emitted type, which has foo but not bar.
If you've got an implementation for MakeDynamicType<T>, and assuming your interface has only simple {get; set;} properties, wouldn't this be as simple as:
public static IList<T> ToInterfacedObjects<T>(this IEnumerable<T> data) where T : class
{
var myType = MakeDynamicType<T>();
var list = new List<T>();
foreach (var datum in data)
{
var obj = (T)Activator.CreateInstance(myType);
foreach (var pi in typeof(T).GetProperties())
{
var val = pi.GetValue(datum);
pi.SetValue(obj, val);
}
list.Add(obj);
}
return list;
}
I am trying to create a c# class dynamically at run time.
using System;
class Hist
{
private int? _min;
private int? _max;
public int? min
{
get{return _min;}
set {_min = value;}
}
public int? max
{
get{return _max;}
set {_max = value;}
}
}
public class ProcessData
{
private string _id;
private string _source;
private int? _currentValue;
private Hist _hist;
public Hist hist
{
get { return _hist; }
set{ _hist = value; }
}
public string id
{
get {return _id;}
set { _id = value; }
}
public string source
{
get {return _source;}
set { _source = value; }
}
public int? currentValue
{
get {return _currentValue;}
set { _currentValue = value; }
}
public int? min
{
get { return (hist != null) ? hist.min : null; }
}
public int? max
{
get { return (hist != null) ? hist.max : null; }
}
}
But i am unable to do this specifically.
return (hist != null) ? hist.max : null;
i just need is the get method for any of the min or max property of ProcessData class.
My code for above task:
var method = parentType.GetMethod("get_" + propertyName);
getPropMthdBldr = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
propertyType, Type.EmptyTypes);
getIl = getPropMthdBldr.GetILGenerator();
var moveTo = getIl.DefineLabel();
getIl.Emit(OpCodes.Ldarg_0);
getIl.EmitCall(OpCodes.Call, parentGetMethod, Type.EmptyTypes);
getIl.Emit(OpCodes.Brtrue_S, moveTo);
getIl.Emit(OpCodes.Ldloca_S, 0);
getIl.Emit(OpCodes.Initobj, typeof(int?));
getIl.Emit(OpCodes.Ldloc_0);
getIl.Emit(OpCodes.Ret);
getIl.MarkLabel(moveTo);
getIl.Emit(OpCodes.Ldarg_0);
getIl.EmitCall(OpCodes.Call, parentGetMethod,Type.EmptyTypes);
getIl.EmitCall(OpCodes.Callvirt, method,Type.EmptyTypes);
getIl.Emit(OpCodes.Ret);
Problem is that you are trying to use local variable that not declared:
getIl.Emit(OpCodes.Ldloca_S, 0); // load address of local variable with index 0 on stack
getIl.Emit(OpCodes.Initobj, typeof(int?)); // initialize local variable
getIl.Emit(OpCodes.Ldloc_0); // load value of local variable with index 0 on stack
You can define required local variable like this:
var local = getIl.DeclareLocal(typeof(int?));
And your code will be valid, but to improve readability I would advise you to use variable local instead index. It could be done like this:
getIl.Emit(OpCodes.Ldloca_S, local); // load address of local variable on stack
getIl.Emit(OpCodes.Initobj, typeof(int?)); // initialize local variable
getIl.Emit(OpCodes.Ldloc, local); // load value of local variable on stack
P.S. I'll put here code that I've used for generation of classes Hist and ProcessData, may be it could be useful for you in some way, in case if my explanation was not sufficient.
Main logic in this helper for property creation:
public static class TypeBuilderExtensions
{
public static PropertyBuilder CreateProperty<T>(this TypeBuilder builder, string name) => CreateProperty(builder, typeof(T), name);
public static PropertyBuilder CreateProperty(this TypeBuilder builder, Type propertyType, string name)
{
var field = builder.DefineField($"_{name}", propertyType, FieldAttributes.Private);
var getMethodBuilder = builder.DefineMethod($"get_{name}", MethodAttributes.Public, propertyType, Type.EmptyTypes);
var getGenerator = getMethodBuilder.GetILGenerator();
getGenerator.Emit(OpCodes.Ldarg_0);
getGenerator.Emit(OpCodes.Ldfld, field);
getGenerator.Emit(OpCodes.Ret);
var setMethodBuilder = builder.DefineMethod($"set_{name}", MethodAttributes.Public, typeof(void), new[] { propertyType });
var setGenerator = setMethodBuilder.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Stfld, field);
setGenerator.Emit(OpCodes.Ret);
var propertyBuilder = builder.DefineProperty(name, PropertyAttributes.None, propertyType, Type.EmptyTypes);
propertyBuilder.SetGetMethod(getMethodBuilder);
propertyBuilder.SetSetMethod(setMethodBuilder);
return propertyBuilder;
}
public static PropertyBuilder CreateCalculatedProperty<T>(this TypeBuilder builder, string name, MethodInfo getObject, MethodInfo getObjectProperty) => CreateCalculatedProperty(builder, typeof(T), name, getObject, getObjectProperty);
public static PropertyBuilder CreateCalculatedProperty(this TypeBuilder builder, Type propertyType, string name, MethodInfo getObject, MethodInfo getObjectProperty)
{
var getMethodBuilder = builder.DefineMethod($"get_{name}", MethodAttributes.Public, propertyType, Type.EmptyTypes);
var getGenerator = getMethodBuilder.GetILGenerator();
var label = getGenerator.DefineLabel();
var local = getGenerator.DeclareLocal(propertyType);
getGenerator.Emit(OpCodes.Ldarg_0);
getGenerator.Emit(OpCodes.Callvirt, getObject);
getGenerator.Emit(OpCodes.Brtrue, label);
getGenerator.Emit(OpCodes.Ldloca_S, local);
getGenerator.Emit(OpCodes.Initobj, propertyType);
getGenerator.Emit(OpCodes.Ldloc, local);
getGenerator.Emit(OpCodes.Ret);
getGenerator.MarkLabel(label);
getGenerator.Emit(OpCodes.Ldarg_0);
getGenerator.Emit(OpCodes.Callvirt, getObject);
getGenerator.Emit(OpCodes.Callvirt, getObjectProperty);
getGenerator.Emit(OpCodes.Ret);
var propertyBuilder = builder.DefineProperty(name, PropertyAttributes.None, propertyType, Type.EmptyTypes);
propertyBuilder.SetGetMethod(getMethodBuilder);
return propertyBuilder;
}
}
Here is class creation itself:
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("TestAssembly"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("TestModule");
var histBuilder = moduleBuilder.DefineType("Hist");
var minProperty = histBuilder.CreateProperty<int?>("min");
var maxProperty = histBuilder.CreateProperty<int?>("max");
var processDataBuilder = moduleBuilder.DefineType("ProcessData");
var histProperty = processDataBuilder.CreateProperty(histBuilder, "hist");
processDataBuilder.CreateProperty<string>("id");
processDataBuilder.CreateProperty<string>("source");
processDataBuilder.CreateProperty<int?>("currentValue");
processDataBuilder.CreateCalculatedProperty<int?>("min", histProperty.GetMethod, minProperty.GetMethod);
processDataBuilder.CreateCalculatedProperty<int?>("max", histProperty.GetMethod, maxProperty.GetMethod);
And finally primitive validation of created classes:
void ValidateProperty(object instance, string name, object value, bool setValue = true)
{
var type = instance.GetType();
var property = type.GetProperty(name);
if (setValue) property.SetValue(instance, value);
var result = property.GetValue(instance);
var equals = property.PropertyType.IsValueType && value != null ? value.Equals(result) : value == result;
if (!equals)
throw new InvalidDataException("Property not valid");
}
var histType = histBuilder.CreateType();
var histInstance = Activator.CreateInstance(histType);
ValidateProperty(histInstance, "min", 12);
ValidateProperty(histInstance, "max", 21);
var processDataType = processDataBuilder.CreateType();
var processDataInstance = Activator.CreateInstance(processDataType);
ValidateProperty(processDataInstance, "hist", histInstance);
ValidateProperty(processDataInstance, "id", "Test!");
ValidateProperty(processDataInstance, "source", "Source#");
ValidateProperty(processDataInstance, "currentValue", 126);
ValidateProperty(processDataInstance, "min", 12, false);
ValidateProperty(processDataInstance, "max", 21, false);
ValidateProperty(processDataInstance, "hist", null);
ValidateProperty(processDataInstance, "min", null, false);
ValidateProperty(processDataInstance, "max", null, false);
I'm trying to make this code in IL using ILGenerator.Emit
class Foo
{
...
}
public class TestClass
{
public static void test()
{
Type t = typeof(Foo);
foreach(PropertyInfo p in t.GetProperties())
{
GenerateVar(p.PropertyInfo);
}
}
public static object GenerateVar(Type var)
{
if (var == typeof(Int32))
{
return 5;
}
else if (var == typeof(Char))
{
return 'a';
}
return null;
}
}
This is what I've done so far, and had some complications:
MethodInfo mi = TestClass.GetType().GetMethod("GenerateVar",
BindingFlags.Public |
BindingFlags.Instance);
ILGenerator generator = mb.GetILGenerator();
LocalBuilder propertyType;
LocalBuilder TestClass = mb_gen.DeclareLocal(typeof(TestClass));
foreach (PropertyInfo pi in t.GetProperties())
{
propertyType = mb_gen.DeclareLocal(pi.PropertyType);
//loads into the stack the current PropertyType and the method class
generator.Emit(OpCodes.Ldloc, TestClass);
generator.Emit(OpCodes.LdLoc, propertyType);
//calls GenerateVar(Type var) to get a PropertyType var
generator.Emit(OpCodes.Callvirt, mi);
}
It gives me the following exception:
-> expected type: System.Type , Received type: System.String
System.String is the property type that was given by: pi.PropertyType;
What am I doing wrong?
Thanks in advance
As thehennyy comment, if you can give us the full code we will can to help better. I'm trying to help here because I guess what you try to do.
So I based here on your C# code. As I understand you want to create a method that get properties of type (Foo in your case) and foreach of them, get some value based on type.
Here is a snippet of doing it for first property of the type. To complete the code you need to emit the loop, or, like you wrote in your question, loop on the properties in your C# code and emit the code for each property one after one.
static void CallGenerateVar()
{
var dm = new DynamicMethod("CallGenerateVar", typeof(object), Type.EmptyTypes, typeof(TestClass));
MethodInfo generateVarMethod = typeof(TestClass).GetMethod("GenerateVar", BindingFlags.Public | BindingFlags.Instance);
var ilGen = dm.GetILGenerator();
var properties = ilGen.DeclareLocal(typeof(PropertyInfo[]));
var index = ilGen.DeclareLocal(typeof(int));
var propInfo = ilGen.DeclareLocal(typeof(PropertyInfo));
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldtoken, typeof(Foo));
ilGen.Emit(System.Reflection.Emit.OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, typeof(Type).GetMethod("GetProperties", Type.EmptyTypes));
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_1);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_1);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
ilGen.Emit(System.Reflection.Emit.OpCodes.Stloc_2);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ldloc_2);
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, typeof(PropertyInfo).GetMethod("get_PropertyType", BindingFlags.Instance | BindingFlags.Public));
ilGen.Emit(System.Reflection.Emit.OpCodes.Callvirt, generateVarMethod);
ilGen.Emit(System.Reflection.Emit.OpCodes.Ret);
var del = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
var result = del.Invoke();
}
In case our Foo type looks like this:
class Foo
{
public int MyProperty { get; set; }
}
And GenerateVar looks like this:
public object GenerateVar(Type var)
{
if (var == typeof(Int32))
{
return 5;
}
else if (var == typeof(Char))
{
return 'a';
}
return null;
}
It will print 5
I have this architecture.
public void Init()
{
PropertyInfo[] infos = typeof(Transform).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo info in infos)
{
// Save getter
MethodInfo method = info.GetGetMethod();
System.Type returnType = method.ReturnType;
System.Func<Transform, Vector3> fact = GetFactory<Transform, Vector3>(method);
Vector3 v = fact(this.Value);
Debug.Log("Test123 " + v);
//_getters.Add(info.Name, newMethod);
}
}
static System.Func<T, T1> GetFactory<T, T1>(MethodInfo info)
{
return (System.Func<T, T1>)GetFactory(typeof(T), typeof(T1), info);
}
static object GetFactory(System.Type type, System.Type type1, MethodInfo info)
{
System.Type funcType = typeof(System.Func<,>).MakeGenericType(type, type1);
return System.Delegate.CreateDelegate(funcType, info);
}
It even works if method.ReturnType is Vector3.
But I want the func<Transform, Vector3> to be func<Transform, ReturnType>.
I have no idea doing this.
Does someone of you know how I can do this?
And I also have no idea how to save the result in a dictionary.
Which type can the dictionary be of?
public Dictionary<string, System.Func<object, object>> _getters = new Dictionary<string, System.Func<object, object>>();
Edit: No ideas?
From what I get from the comment, is that you want to access getters through a string key? If that is the case, you might want to use the code sample below.
The entity you want to access:
class Entity
{
public int Foo { get { return 42; } }
public string Bar { get { return "Magic"; } }
}
The class that allows you to access the properties by name:
class PropertyCaller<T>
{
// Static for each type T
private static readonly IDictionary<string, Func<T, object>> _propertyLookup;
static PropertyCaller()
{
_propertyLookup = new Dictionary<string, Func<T, object>>();
Type objectType = typeof (T);
foreach (PropertyInfo prop in objectType.GetProperties())
{
const BindingFlags num = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
MethodInfo getMethod = prop.GetGetMethod(true);
_propertyLookup.Add(prop.Name, item => getMethod.Invoke(item, num, null, null, null));
}
}
public static object Call(T obj, string propertyName)
{
Func<T, object> f;
if (!_propertyLookup.TryGetValue(propertyName, out f))
{
throw new InvalidOperationException();
}
return f(obj);
}
}
Example usage:
Entity e = new Entity();
var a = PropertyCaller<Entity>.Call(e, "Foo"); // 42
var b = PropertyCaller<Entity>.Call(e, "Bar"); // Magic
i write some method for create class and property in run time with Reflection.Emit
my code is:
public class DynamicLibraryProperties
{
public string PropName { get; set; }
public Type PropType { get; set; }
public string DefaultValue { get; set; }
}
public class GenerateDynamicClass
{
public static void GenerateLegacyStructureObject(string libraryName, string className, List<DynamicLibraryProperties> properties)
{
ILGenerator ilgen = default(ILGenerator);
string library = string.Concat(libraryName, ".dll");
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(libraryName), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(libraryName, library);
TypeBuilder legacyBuilder = modBuilder.DefineType(string.Concat(libraryName, ".", className), TypeAttributes.Class | TypeAttributes.Public);
//Field Builder - Based on number of months add so many fields
foreach (DynamicLibraryProperties p in properties)
{
FieldBuilder field = legacyBuilder.DefineField(string.Concat("_", p.PropName), p.PropType, FieldAttributes.Private);
PropertyBuilder nameProp = legacyBuilder.DefineProperty(p.PropName, PropertyAttributes.HasDefault, p.PropType, null);
Type[] types = new Type[] { p.PropType };
dynamic typeConvertor = TypeDescriptor.GetConverter(p.PropType);
dynamic defaultValue = typeConvertor.ConvertFromString(p.DefaultValue);
ConstructorInfo ctor = typeof(DefaultValueAttribute).GetConstructor(types);
CustomAttributeBuilder customAttrib = new CustomAttributeBuilder(ctor, new object[] { defaultValue });
nameProp.SetCustomAttribute(customAttrib);
MethodAttributes getAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
MethodBuilder getNameBuilder = legacyBuilder.DefineMethod(string.Concat("get_", p.PropName), getAttr, p.PropType, Type.EmptyTypes);
ilgen = getNameBuilder.GetILGenerator(); ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, field);
ilgen.Emit(OpCodes.Ret);
MethodBuilder setNameBuilder = legacyBuilder.DefineMethod(string.Concat("set_", p.PropName), getAttr, null, new Type[] { p.PropType });
ilgen = setNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Stfld, field); ilgen.Emit(OpCodes.Ret);
nameProp.SetGetMethod(getNameBuilder);
nameProp.SetSetMethod(setNameBuilder);
}
Type objType = Type.GetType("System.Object");
ConstructorInfo objCtor = objType.GetConstructor(Type.EmptyTypes);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, objCtor);
ilgen.Emit(OpCodes.Ret);
legacyBuilder.CreateType();
asmBuilder.Save(library);
}
}
and use this code like this
List<DynamicLibraryProperties> props = new List<DynamicLibraryProperties>();
props.Add(new DynamicLibraryProperties
{
PropName = "201203", PropType = typeof(float),DefaultValue = "0"
});
props.Add(new DynamicLibraryProperties { PropName = "201204", PropType = typeof(float) ,DefaultValue = "0"});
GenerateDynamicClass.GenerateLegacyStructureObject("test", "test", props);
Now i want create instance of Test class and set value for property value but i don't no how to do it, please help me , thanks all.
You can use Activator.CreateInstance for this, for that you need Type of your test class.
Change the method as below.
public static Type GenerateLegacyStructureObject(string libraryName, string className, List<DynamicLibraryProperties> properties)
{
//your code
Type t = legacyBuilder.CreateType();
asmBuilder.Save(library);
return t;
}
Then use it like this
Type testType = GenerateDynamicClass.GenerateLegacyStructureObject("test", "test", props);
object test = Activator.CreateInstance(testType);
Hope this helps