ML.NET Create Prediction Engine using Dynamic Class - c#

I have an ML.NET application where I have to create interface IDataView dynamically after compile time to be used for training. I found this thread and I've been able to successfully create a dynamic interface for the training data set and then use it to train a model. My problem comes in when I try to use that same interface in order to create a prediction using that trained model. The docs show that you should create a prediction engine where you have to define both the input and output class types in order to create the engine. Something like:
mlContext.Model.CreatePredictionEngine<TSrc,TDst>(ITransformer, DataViewSchema)
where TSrc and TDst are class types that are known at compile time. My problem is that I don't know the structure of the input class type at compile time and have to create a dynamic interface for the input data source. The output class object can be defined since the parameters are known, but I'm unsure how to proceed with a dynamic input.
I thought I could maybe try to use something like GetType() on the interface but it says that "implicitly-typed variables cannot have multiple declarators". My simplified example looks like this:
public class ModelOutput
{
public string PredictedLabel { get; set; }
public float[] Score { get; set; }
}
public class MakePrediction
{
protected void Solve(IDataView data, ITransformer model)
{
var mlContext = new MLContext();
var engine = mlContext.Model.CreatePredictionEngine<data.GetType(), ModelOutput>(model, data.Schema);
}
}

It's possible to generate a runtime class that has all the fields listed in the DataViewSchema. This will allow you to create a PredictionEngine.
You won't be able to create the PredictionEngine directly, you'll have to invoke it. Here is some sample code:
// Create runtime type from fields and types in a DataViewSchema
var runtimeType = ClassFactory.CreateType(dataViewSchema);
dynamic dynamicPredictionEngine;
var genericPredictionMethod = mlContext.Model.GetType().GetMethod("CreatePredictionEngine", new[] { typeof(ITransformer), typeof(DataViewSchema) });
var predictionMethod = genericPredictionMethod.MakeGenericMethod(runtimeType, typeof(PricePrediction));
dynamicPredictionEngine = predictionMethod.Invoke(mlContext.Model, new object[] { model, dataViewSchema });
To actually use the PredictionEngine (dynamicPredictionEngine), use a call similar to this:
var predictMethod = dynamicPredictionEngine.GetType().GetMethod("Predict", new[] { runtimeType });
var predict = predictMethod.Invoke(dynamicPredictionEngine, new[] { inputObject });
I used modified copy (ClassFactory above) of the source from this wonderful example of creating runtime classes. My copy accepts a DataViewSchema to auto generate the requires class. That code is below:
using Microsoft.ML;
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
public static class ClassFactory
{
private static AssemblyName _assemblyName;
public static object CreateObject(string[] PropertyNames, Type[] Types)
{
_assemblyName = new AssemblyName("DynamicInput");
if (PropertyNames.Length != Types.Length)
{
Console.WriteLine("The number of property names should match their corresponding types number");
}
TypeBuilder DynamicClass = CreateTypeBuilder();
CreateConstructor(DynamicClass);
for (int ind = 0; ind < PropertyNames.Count(); ind++)
CreateProperty(DynamicClass, PropertyNames[ind], Types[ind]);
Type type = DynamicClass.CreateType();
return Activator.CreateInstance(type);
}
public static Type CreateType(DataViewSchema dataViewSchema)
{
_assemblyName = new AssemblyName("DynamicInput");
TypeBuilder DynamicClass = CreateTypeBuilder();
CreateConstructor(DynamicClass);
foreach (var item in dataViewSchema)
{
CreateProperty(DynamicClass, item.Name, item.Type.RawType);
}
return DynamicClass.CreateType();
}
private static TypeBuilder CreateTypeBuilder()
{
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType(_assemblyName.FullName
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, null);
return typeBuilder;
}
private static void CreateConstructor(TypeBuilder typeBuilder)
{
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
}
private static void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = typeBuilder.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 = typeBuilder.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);
}
}

Look up MethodInfo.MakeGenericMethod()

Related

Self referencing class propery with TypeBuilder

I try to build runtime type builder, but i have encountered an egg and chicken problem with self referencing type property. I'm using TypeBuilder and basically what I do is I pass a list of property names and their types and i generate a type — and that works fine as long as the type is known by the time of creation. However I'd like to achieve this basic concept
public class Person
{
public string Name { get; set; }
public Person Child { get; set; }
}
And I'm pretty much stuck. How do I tell TypeBuilder that I want a property of type that has not been created yet? How CLR does this?
My current code
public class FieldDescription
{
public string FieldName { get; set; }
public Type FieldType { get; set; }
}
public static class CustomTypeBuilder
{
public static Type CompileResultType(List<FieldDescription> fields, string TypeName)
{
TypeBuilder tb = GetTypeBuilder(TypeName);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
foreach (var field in fields)
CreateProperty(tb, field);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder(string typeSignature)
{
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
FieldBuilder fieldBuilder = tb.DefineField("_ToStringValue", typeof(string), FieldAttributes.Private);
return tb;
}
private static void CreateProperty(TypeBuilder tb, FieldDescription field)
{
string propertyName = field.FieldName;
Type propertyType = field.FieldType ?? tb;
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 | MethodAttributes.Virtual, 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 | MethodAttributes.Virtual,
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);
}
}
CreateProperty allows to pass FieldDescription field with null set for field.FieldType, in this case TypeBuilder tb type will be used as a property type.
So just pass null for FieldType and everything should work:
var compileResultType = CustomTypeBuilder.CompileResultType(new List<FieldDescription>
{
new() { FieldName = "Test1", FieldType = typeof(string) },
new() { FieldName = "Test2", FieldType = null } // property of the type being created
},
"TypeToTest");
var instance = Activator.CreateInstance(compileResultType);
var test1PI = compileResultType.GetProperty("Test1");
var test2PI = compileResultType.GetProperty("Test2");
test1PI.SetValue(instance, "test");
test2PI.SetValue(instance, instance);
Console.WriteLine(test1PI.GetValue(instance)); // prints test
Console.WriteLine(test2PI.GetValue(instance)); // prints TypeToTest

Dynamic type shadow base class's property and set to protected using Reflection.Emit

I work for several days try to shadow base class's property and set the derived class property to protected using Reflection.Emit. When I create a derived class and set new to the base property, call GetProperties() it only show one property with the name and the derived class property is not public, but the dynamic type call GetProperties() show two properties with the same name appear(base property is public and dynamic type is not public). here is my code.
namespace ILHiddenProperty
{
interface IILName
{
string Name { get; set; }
}
public class ClassName : IILName
{
public string Name { get; set; } = "ClassName";
}
public class ChildName : ClassName
{
protected new string Name { get; set; } = "ChildName";
}
public class NameILGenerator
{
public static Type ILType()
{
AssemblyName aname = new AssemblyName("MyAssembly");
AppDomain currentDomain = AppDomain.CurrentDomain; // Thread.GetDomain();
AssemblyBuilder asmbuilder = currentDomain.DefineDynamicAssembly(aname,
AssemblyBuilderAccess.Run);
ModuleBuilder mbuilder = asmbuilder.DefineDynamicModule("EmitMethods");
TypeBuilder tbuilder = mbuilder.DefineType("ILName", TypeAttributes.Public,typeof(ClassName));
FieldBuilder fName = tbuilder.DefineField("_name", typeof(System.String), FieldAttributes.Private);
PropertyBuilder pName = tbuilder.DefineProperty("Name", PropertyAttributes.HasDefault, typeof(System.String), null);
//Getter
MethodBuilder mNameGet = tbuilder.DefineMethod("get_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
typeof(System.String),
Type.EmptyTypes);
ILGenerator nameGetIL = mNameGet.GetILGenerator();
nameGetIL.Emit(OpCodes.Ldarg_0);
nameGetIL.Emit(OpCodes.Ldfld, fName);
nameGetIL.Emit(OpCodes.Ret);
//Setter
MethodBuilder mNameSet = tbuilder.DefineMethod("set_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null,
new Type[] { typeof(System.String) });
ILGenerator nameSetIL = mNameSet.GetILGenerator();
nameSetIL.Emit(OpCodes.Ldarg_0);
nameSetIL.Emit(OpCodes.Ldarg_1);
nameSetIL.Emit(OpCodes.Stfld, fName);
nameSetIL.Emit(OpCodes.Ret);
pName.SetGetMethod(mNameGet);
pName.SetSetMethod(mNameSet);
return tbuilder.CreateType();
}
}
}
namespace ILHiddenProperty
{
class Program
{
static void Main(string[] args)
{
PrintNameProperty(typeof(ClassName));
PrintNameProperty(typeof(ChildName));
PrintNameProperty(NameILGenerator.ILType());
Console.Read();
}
public static void PrintNameProperty(Type nameType)
{
var props = nameType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach(var prop in props)
{
Console.WriteLine("{0}.{1} IsPublic:{2}",nameType.Name, prop.Name, prop.GetMethod.IsPublic);
}
}
}
}
I try to add MethodAttributes.NewSlot it did not work. When I change MethodAttributes.Family to MethodAttributes.Public there is a AmbiguousMatchException.
I searched for this Overriding property definitions with Reflection.Emit and change ILType to not define the property but only the get and set functions
public static Type ILType()
{
AssemblyName aname = new AssemblyName("MyAssembly");
AppDomain currentDomain = AppDomain.CurrentDomain; // Thread.GetDomain();
AssemblyBuilder asmbuilder = currentDomain.DefineDynamicAssembly(aname,
AssemblyBuilderAccess.Run);
ModuleBuilder mbuilder = asmbuilder.DefineDynamicModule("EmitMethods");
TypeBuilder tbuilder = mbuilder.DefineType("ILName", TypeAttributes.Public,typeof(ClassName));
FieldBuilder fName = tbuilder.DefineField("_name", typeof(System.String), FieldAttributes.Private);
//PropertyBuilder pName = tbuilder.DefineProperty("Name", PropertyAttributes.HasDefault, typeof(System.String), null);
//Getter
MethodBuilder mNameGet = tbuilder.DefineMethod("get_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
typeof(System.String),
Type.EmptyTypes);
ILGenerator nameGetIL = mNameGet.GetILGenerator();
nameGetIL.Emit(OpCodes.Ldarg_0);
nameGetIL.Emit(OpCodes.Ldfld, fName);
nameGetIL.Emit(OpCodes.Ret);
//Setter
MethodBuilder mNameSet = tbuilder.DefineMethod("set_Name", MethodAttributes.Family |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null,
new Type[] { typeof(System.String) });
ILGenerator nameSetIL = mNameSet.GetILGenerator();
nameSetIL.Emit(OpCodes.Ldarg_0);
nameSetIL.Emit(OpCodes.Ldarg_1);
nameSetIL.Emit(OpCodes.Stfld, fName);
nameSetIL.Emit(OpCodes.Ret);
//pName.SetGetMethod(mNameGet);
//pName.SetSetMethod(mNameSet);
return tbuilder.CreateType();
}
it shows one property but the property is Public. So how can i set the property to protected?
Fixed
Get method return type of String
You should use CallingConventions.HasThis when you define your property :
tbuilder.DefineProperty("Name",
PropertyAttributes.HasDefault,
CallingConventions.HasThis,
typeof(System.String),
null);
You can have more information here : HasThis & ExplicitThis calling conventions
By the way, it helps to call asmBuilder.Save("xxx.dll") after you create the type. It allows you to get the assembly file and decompile it using ILSpy. You will have to use AssemblyBuilderAccess.RunAndSave when you call DefineDynamicAssembly and specify a fileName when calling DefineDynamicModule.
There is also one mistake in your code, your getter return an Int32 whereas the property is of type String

C#: Why I could not see my Class (that was created dynamically) properties

I am going to create a class builder class. It work properly and my class is created base on data that I need. But I could not see the properties that were added to class.
it is my class builder class:
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace aitClassBuilder
{
public interface IclassBuilder
{
float Read(Int32 first, Int32 second);
string Write();
}
public class ClassBuilder : IclassBuilder
{
AssemblyName asemblyName;
public ClassBuilder(string ClassName, string ClassId)
{
this.asemblyName = new AssemblyName(ClassName);
}
public object CreateObject()
{
TypeBuilder DynamicClass = this.CreateClass();
this.CreateConstructor(DynamicClass);
CreateProperty(DynamicClass, "ColumnId", Type.GetType("System.Int32"));
CreateProperty(DynamicClass, "ColumnName", Type.GetType("System.String"));
Type type = DynamicClass.CreateType();
return Activator.CreateInstance(type);
}
private TypeBuilder CreateClass()
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(this.asemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType(this.asemblyName.FullName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, null);
return typeBuilder;
}
private void CreateConstructor(TypeBuilder typeBuilder)
{
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
}
private void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = typeBuilder.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 = typeBuilder.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);
}
public float Read(Int32 first, Int32 second)
{
return first + second;
}
public string Write()
{
string result = "";
return result;
}
}
}
and I use from the class like this:
aitClassBuilder.ClassBuilder myCls =
new ClassBuilder("Sys_Columns", "1003");
object myTbl = myCls.CreateObject();
MessageBox.Show(myTbl.ColumnID);
at end of this code when I want get access to ColumnID property of my class, an Error took place. But when I add the class to watch window, I could see that the properties were added to my class. I dont know why?
Could you help me please?
The error detail is:
Error CS1061 'object' does not contain a definition for 'ColumnID' and no extension method 'ColumnID' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) FormSample E:\New Hafiz\aitClassBuilder\FormSample\Form1.cs 29 Active
As the error message indicates the object type does not have a property called ColumnID. Due to the fact that you cannot cast the object to the actual type, you have to use the dynamic keyword here. So your code will be:
dynamic myTbl = myCls.CreateObject();
MessageBox.Show(myTbl.ColumnID);
Note that you won't have any compile time checks on the types of the properties using this approach.
What is happening there?
0_o.
Why do you generate a whole new class on the fly rather than create yet another Dictionary<string, object>? In case you prefer to stick to strong types (which I assume you do, otherwise why C# ever needed?), an extension method TResult TryGetValue<TResult>(this Dictionary<string, object> #this, string key) might be declared.
Hence 95% of code you showed up will vanish and the problem you started with will... just disappear.
You have to cast your object to (Sys_Columns).
Sys_Columns myTbl = (Sys_Columns)myCls.CreateObject();

Add Attribute to the property dynamically

Following Implementation which is creating class and property dynamically:
public static class MyTypeBuilder
{
public static void CreateNewObject()
{
var myType = CompileResultType();
}
public static Type CompileResultType()
{
TypeBuilder tb = GetTypeBuilder();
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
var fields = new List<Field>() {
new Field("EmployeeID", typeof(int)),
new Field("EmployeeName", typeof(string)),
new Field("Designation", typeof(string))
};
// NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
foreach (var field in fields)
CreateProperty(tb, field.FieldName, field.FieldType);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder()
{
var typeSignature = "MyDynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, 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);
}
}
In same above implementation i want to add attribute for the property
Example
[DelimitedRecord(",")]
[IgnoreEmptyLines()]
private class myDyanmicType
{
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public int EmployeeID;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public String EmployeeName;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public String Designation;
}
so i want to add attribute to the property like
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
how i will achieve this with my code of creating the dynamic class and property
Please help.
Just a simpler and faster approach: Write your appreciated code to a string, then compile it at runtime, and you will get everything ready!
string src = "[DelimitedRecord(\",\")] [IgnoreEmptyLines()] private class ...";
var compParms = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
var csProvider = new CSharpCodeProvider();
CompilerResults compilerResults = csProvider.CompileAssemblyFromSource(compParms, src);
var a = compilerResults.CompiledAssembly; // here you go

Create an interface with properties with Reflection.Emit

I need to generate an interface.
I'va a problem to generate (emit) the virtual properties. It seems they are not generated.
I figure out I'm doing something wrong:
private static TypeBuilder getTypeBuilder()
{
var typeSignature = "DynamicDigitalInput";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicDomain");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Interface |
TypeAttributes.Abstract |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, null);
return tb;
}
private static void createProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
}
In order to generate the interface:
TypeBuilder tb = getTypeBuilder();
createProperty(tb, "p1", String.GetType());
createProperty(tb, "p2", Int32.GetType());
When I perform this:
Type i = tb.CreateType();
System.Reflection.PropertyInfo p1 = type.GetProperty("p1");
p1 is null.
What am I doing wrong?
The property is not defined correctly. In order for GetProperty to work, the property must have at least one public getter or setter. Right now, is does not have even one getter or setter, so they never can be public.
So, you have to create a public get-method and/or a public set-method (using the MethodBuilder). Try this:
private static void createProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder methodBuilder = tb.DefineMethod("get_" + propertyName, MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.Public);
propertyBuilder.SetGetMethod(methodBuilder);
}

Categories

Resources