I'm trying to acces the property of the class my Methodbuilder method is being defined in.
This is my current code:
Type[] types = { typeof(HttpListenerContext) };
TypeBuilder tb = GetTypeBuilder(type.Name);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
MethodBuilder mB = tb.DefineMethod("Init", MethodAttributes.Public | MethodAttributes.Virtual, null, types);
ILGenerator il = mB.GetILGenerator();
il.Emit(OpCodes.Ldstr, typeof(Page).GetProperty("_POST").GetValue(??));
il.Emit(OpCodes.Call, typeof(DataSet).GetMethod("SetData"));
il.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mB, typeof(Page).GetMethod("Init"));
try
{
Type tc = tb.CreateType();
Page test = (Page)Activator.CreateInstance(tc);
test.Init();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
This is is class I'm trying to get the property from:
public class Page
{
public Dictionary<string, string> _POST { get; set; }
public Dictionary<string, string> _GET { get; set; }
public Head Headers { get; set; }
public string ContentType { get; set; }
public int StatusCode = 200;
public virtual void Init(HttpListenerContext ctx = null) { }
public virtual void Load() { }
public virtual string Send() { return ""; }
public virtual string Send(string response) { return ""; }
}
The current typebuilder has Page as parent, how can I get a nonstatic value set in my typebuilder class? Like how could I get my method to Console.WriteLine the value of _POST?
private TypeBuilder GetTypeBuilder(string name)
{
string typeSignature = name;
AssemblyName aN = new AssemblyName(typeSignature);
AssemblyBuilder aB = AppDomain.CurrentDomain.DefineDynamicAssembly(aN, AssemblyBuilderAccess.Run);
ModuleBuilder mB = aB.DefineDynamicModule("MainModule");
TypeBuilder tB = mB.DefineType(typeSignature + "h",
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
typeof(Page));
return tB;
}
ILGenerator il = mB.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, typeof(Page).GetProperty("ContentType").GetGetMethod());
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
il.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mB, typeof(Page).GetMethod("Init"));
I'm setting the value of ContentType before I'm getting it with my function.
It seems like you're creating an instance method on a type that inherits from Page. If that's the case, this is the code you want:
il.Emit(OpCodes.Ldarg_0); // Load the this reference
il.Emit(OpCodes.Call, typeof(Page).GetProperty("_POST").GetGetMethod());
Also, note that DataSet doesn't have a SetData method - if that's an extension method, you need to use the real type where it's defined rather than DataSet.
Related
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
I am trying to build dynamic types, inherited from a base object, based on a definition object (fieldnames/types) and then apply (potentially multiple) interfaces to that.
The base type has an object array to store values. The getters and setters use a generic method in the base type to save a specific type to an array location.
The "CreateType" works, but when I try to instantiate the object, I get:
System.InvalidProgramException : Common Language Runtime detected an invalid program.
I can't tell where the failure occurs.
Here is the Object definition:
public class UTObjectDef : IUTObjectDef
{
List<UTFieldDef> fieldDefs = new List<UTFieldDef>();
Dictionary<string, Type> interfaces = new Dictionary<string,Type>();
List<string> nameMap = new List<String>();
public string Name {get; set;}
public IUTFieldDef[] FieldDefs {
get {
return fieldDefs.ToArray();
}
}
public Type[] Interfaces {
get {
return interfaces.Values.ToArray();
}
}
public UTObjectDef(string name) {
Name = name;
}
public UTObjectDef(Type fromInterface) {
PropertyInfo[] props = fromInterface.GetProperties();
Name = fromInterface.Name;
if (Name.ToUpper().StartsWith("I")) {
Name = Name.Substring(1);
}
foreach( PropertyInfo prop in props) {
AddField(prop.Name, prop.PropertyType);
}
interfaces.Add(Name, fromInterface);
}
public void AddField(string name, Type fieldType)
{
var fieldDef = new UTFieldDef(name, fieldType);
fieldDefs.Add(fieldDef);
nameMap.Add(name);
}
public int FieldIndex(string fieldName) {
return nameMap.IndexOf(fieldName);
}
}
And the field definition:
public class UTFieldDef : IUTFieldDef
{
public string FieldName {get; set;}
public Type FieldType {get; set;}
public int? Length {get; set;}
public int? Decimals {get; set;}
public UTFieldDef(string fieldName, Type fieldType) {
FieldName = fieldName;
FieldType = fieldType;
}
}
The base type (Note: The constructor sets the arrays to the right size based on the field count), and the static UTObjectDef is populated through an Initialize static method, added in the TypeBuilder):
public class UTObject : IUTObject{
protected Object?[] values = new Object[0];
protected Object?[] origValues = new Object[0];
public T? getValue<T>(int index) {
return (T?)values[index];
}
public void setValue<T>(int index, T? value) {
values[index] = value;
}
}
And the dynamic object construction:
public static void buildTypes() {
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);
Type baseType = typeof(UTObject.UTObject);
Type objDefType = typeof(UTObjectDef);
var valuesField = baseType.GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
var origValuesField = baseType.GetField("origValues", BindingFlags.NonPublic | BindingFlags.Instance);
foreach (UTObjectDef oDef in objectDefs.Values) {
TypeBuilder tb = mb.DefineType( oDef.Name, TypeAttributes.Public, baseType);
// Create a static field to hold the value.
const string FieldName = "ObjectDef";
var field = tb.DefineField(
FieldName,
objDefType,
FieldAttributes.Static | FieldAttributes.InitOnly | FieldAttributes.Public);
// Create a method to initialize the field.
const string InitializeMethodName = "Initialize";
var initMethod = tb.DefineMethod(
InitializeMethodName,
MethodAttributes.Static | MethodAttributes.Private,
CallingConventions.Standard,
typeof(void),
new[] { objDefType });
var il = initMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Stsfld, field);
il.Emit(OpCodes.Ret);
System.Type[] param = {};
Type invalOp = typeof(InvalidOperationException);
ConstructorInfo invOpExInfo = invalOp.GetConstructor(
Type.EmptyTypes
);
ConstructorInfo baseCon = baseType.GetConstructor(Type.EmptyTypes);
ConstructorBuilder ctor = tb.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, param );
ILGenerator cil = ctor.GetILGenerator();
Label isInit = cil.DefineLabel(); // define label to jump in case condition is false
MethodInfo getFldDefsInfo = objDefType.GetMethod("get_FieldDefs");
cil.Emit(OpCodes.Ldarg_0);
cil.Emit(OpCodes.Call, baseCon );
cil.Emit(OpCodes.Ldsfld, field);
cil.Emit(OpCodes.Ldnull);
cil.Emit(OpCodes.Ceq);
cil.Emit(OpCodes.Brfalse, isInit);
cil.Emit(OpCodes.Nop);
cil.Emit(OpCodes.Ldstr, "Not Initialized");
cil.Emit(OpCodes.Newobj, invOpExInfo);
cil.ThrowException(invalOp);
cil.MarkLabel(isInit);
cil.Emit(OpCodes.Nop);
cil.Emit(OpCodes.Ldarg_0);
cil.Emit(OpCodes.Call, getFldDefsInfo);
cil.Emit(OpCodes.Ldlen);
cil.Emit(OpCodes.Conv_I4);
cil.Emit(OpCodes.Newarr, typeof(System.Object));
cil.Emit(OpCodes.Stfld, valuesField);
cil.Emit(OpCodes.Ldarg_0);
cil.Emit(OpCodes.Call, getFldDefsInfo);
cil.Emit(OpCodes.Ldlen);
cil.Emit(OpCodes.Conv_I4);
cil.Emit(OpCodes.Newarr, typeof(System.Object));
cil.Emit(OpCodes.Stfld, origValuesField);
cil.Emit(OpCodes.Ret);
MethodInfo[] methods = typeof(UTObject.UTObject).GetMethods();
MethodInfo? getMethod = null;
MethodInfo? setMethod = null;
foreach(MethodInfo mi in methods) {
if (mi.Name.Contains("getValue") && mi.IsGenericMethod) {
getMethod = mi;
}
if (mi.Name.Contains("setValue") && mi.IsGenericMethod) {
setMethod = mi;
}
}
for (int i = 0; i < oDef.FieldDefs.Length; i++ )
{
IUTFieldDef fDef = oDef.FieldDefs[i];
PropertyBuilder fldPropBldr = tb.DefineProperty(fDef.FieldName,
PropertyAttributes.None,
fDef.FieldType,
null);
MethodBuilder getMethodBuilder = tb.DefineMethod("get_" + fDef.FieldName,
getSetAttr,
fDef.FieldType,
Type.EmptyTypes);
if (getMethod != null) {
ILGenerator GetPropGetIL = getMethodBuilder.GetILGenerator();
LocalBuilder fldIdx = GetPropGetIL.DeclareLocal(typeof(Int32));
MethodInfo getMethodInfo = getMethod.MakeGenericMethod(fDef.FieldType);
GetPropGetIL.Emit(OpCodes.Ldc_I4, i);
GetPropGetIL.Emit(OpCodes.Stloc, fldIdx);
GetPropGetIL.Emit(OpCodes.Ldarg_0);
GetPropGetIL.Emit(OpCodes.Ldloc, fldIdx);
GetPropGetIL.Emit(OpCodes.Call, getMethodInfo);
GetPropGetIL.Emit(OpCodes.Ret);
}
MethodBuilder setMethodBuilder = tb.DefineMethod("set_" + fDef.FieldName,
getSetAttr,
null,
new Type[] { fDef.FieldType });
if (setMethod != null) {
ILGenerator SetPropGetIL = setMethodBuilder.GetILGenerator();
LocalBuilder fldIdx = SetPropGetIL.DeclareLocal(typeof(Int32));
SetPropGetIL.Emit(OpCodes.Ldc_I4, i);
SetPropGetIL.Emit(OpCodes.Stloc, fldIdx);
SetPropGetIL.Emit(OpCodes.Ldarg_0);
SetPropGetIL.Emit(OpCodes.Ldloc, fldIdx);
SetPropGetIL.Emit(OpCodes.Call, setMethod.MakeGenericMethod(fDef.FieldType));
SetPropGetIL.Emit(OpCodes.Nop);
SetPropGetIL.Emit(OpCodes.Ret);
}
fldPropBldr.SetGetMethod(getMethodBuilder);
fldPropBldr.SetSetMethod(setMethodBuilder);
}
/* foreach(Type interfaceType in oDef.Interfaces) {
tb.AddInterfaceImplementation(interfaceType);
}
*/
Type? newType = tb.CreateType();
// Invoke the initializer method using reflection, passing the provided value to initialize the new field.
MethodInfo initMethodInfo = newType.GetMethod(InitializeMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (initMethodInfo != null) {
initMethodInfo.Invoke(null, new object[] { oDef });
}
foreach(Type interfaceType in oDef.Interfaces) {
objectTypesByInterface.Add(interfaceType.Name, newType);
}
}
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()
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
I want to know how to generator the following method myMethod with ilGenerator.
public class MyClass {
private MyField myField;
public int myMethod(int b) {
return myField.someMethod(b);
}
}
Can someone help me ?
class Program
{
static MethodAttributes attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
static Type CreateType() {
var myDomain = Thread.GetDomain();
var myAsmName = new AssemblyName { Name = "Demo" };
var myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
var moudle = myAsmBuilder.DefineDynamicModule("DemoModule", "Demo.dll");
var typeBuilder = moudle.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.BeforeFieldInit);
var fieldBuilder = typeBuilder.DefineField("myField", typeof(MyField), FieldAttributes.Private);
var ctorBuilder = typeBuilder.DefineConstructor(attrs, CallingConventions.HasThis | CallingConventions.Standard, Type.EmptyTypes);
var methodBuilder = typeBuilder.DefineMethod("MyMethod", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(int), new[] { typeof(int) });
var ctorILGen = ctorBuilder.GetILGenerator();
var ilGen = methodBuilder.GetILGenerator();
var someMethod = fieldBuilder.FieldType.GetMethod("SomeMethod");
ctorILGen.Emit(OpCodes.Ldarg_0);
ctorILGen.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
ctorILGen.Emit(OpCodes.Ldarg_0);
ctorILGen.Emit(OpCodes.Newobj, fieldBuilder.FieldType.GetConstructor(Type.EmptyTypes));
ctorILGen.Emit(OpCodes.Stfld, fieldBuilder);
ctorILGen.Emit(OpCodes.Ret);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fieldBuilder);
ilGen.Emit(OpCodes.Ldarg_1);
ilGen.Emit(OpCodes.Callvirt, someMethod);
ilGen.Emit(OpCodes.Ret);
return typeBuilder.CreateType();
}
static void Main(string[] args) {
var type = CreateType();
dynamic instance = Activator.CreateInstance(type);
Console.WriteLine(instance.MyMethod(10));
}
}
will generate
public class MyClass
{
private MyField myField;
public MyClass() {
myField = new MyField();
}
public int myMethod(int b) {
return myField.SomeMethod(b);
}
}
public class MyField
{
public int SomeMethod(int i) {
return i;
}
}