Properly emit property - c#

I'm writing an interface implementator for simple interfaces like
interface IPoint
{
int X { get; }
int Y { get; }
}
It almost works, but when I try to implement any property I get an error
Signature of the body and declaration in a method implementation do not match
I don't understand why Emit thinks that properties does not match.
Here is code sample:
private static class InterfaceImplementator<T> where T: class
{
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
public static Type Value { get; }
static InterfaceImplementator()
{
var interfaceType = typeof(T);
if (!interfaceType.IsInterface)
{
throw new ArgumentException($"{interfaceType.FullName} should be an interface!");
}
var interfaceProps = interfaceType.GetProperties();
if (interfaceType.GetMethods().Except(interfaceProps.Select(x => x.GetMethod).Concat(interfaceProps.Select(x => x.SetMethod))).Any())
{
throw new ArgumentException($"{interfaceType.FullName} must have properties only!");
}
var tb = Builder.DefineType($"<{interfaceType.Name}>__Implementation", TypeAttributes.Class | TypeAttributes.Sealed);
foreach (var interfaceProp in interfaceProps)
{
var prop = tb.EmitAutoProperty(interfaceProp.Name, interfaceProp.PropertyType);
if (interfaceProp.CanRead)
{
tb.DefineMethodOverride(prop.GetMethod, interfaceProp.GetMethod);
}
if (interfaceProp.CanWrite)
{
tb.DefineMethodOverride(prop.SetMethod, interfaceProp.SetMethod);
}
}
tb.AddInterfaceImplementation(interfaceType);
Value = tb.CreateType();
}
}
where EmitProperty:
public static PropertyInfo EmitAutoProperty(this TypeBuilder tb, string propertyName, Type propertyType)
{
var backingField = tb.DefineField($"<{propertyName}>k__BackingField", propertyType, FieldAttributes.Private);
var propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
var getMethod = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
var getGenerator = getMethod.GetILGenerator();
getGenerator.Emit(OpCodes.Ldarg_0);
getGenerator.Emit(OpCodes.Ldfld, backingField);
getGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethod);
var setMethod = tb.DefineMethod("set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
var setGenerator = setMethod.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Stfld, backingField);
setGenerator.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setMethod);
return propertyBuilder;
}

Try using the 4-arg DefineMethod call for the get_ and set_ methods so you can define the return type / arg:
var getMethod = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
propertyType,
Type.EmptyTypes);
var setMethod = tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new [] { propertyType });

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

Generate interface implementation with Reflection.Emit for List of given properties

I am using code from this question to generate class from list of property
public class Field
{
public string FieldName;
public Type FieldType;
}
public static class MyTypeBuilder
{
public static Type CompileResultType()
{
TypeBuilder tb = GetTypeBuilder();
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
// NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
foreach (var field in yourListOfFields)
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);
}
}
and I have interface to get/set it's properties to avoid using reflection and dynamic
public interface IDynamicObject
{
T GetProperty<T>(string propertyName);
void SetProperty(string propertyName, object value);
}
Can anybody help me modify this code to generate a class implementing my IDynamicObject interface so it generate something like this (for example two string properties "Str1" and "Str2")? Sadly am not good with Reflection.Emit yet...
public class TestClass : IDynamicObject
{
public string Str1 { get; set; }
public string Str2 { get; set; }
public T GetProperty<T>(string propertyName)
{
switch (propertyName)
{
case nameof(Str1):
return CastObject<T>(Str1);
case nameof(Str2):
return CastObject<T>(Str2);
default: throw new ArgumentException();
}
}
public void SetProperty(string propertyName, object value)
{
switch (propertyName)
{
case nameof(Str1):
Str1 = (string)value;
break;
case nameof(Str2):
Str2 = (string)value;
break;
default: throw new ArgumentException();
}
}
public T CastObject<T>(object input)
{
return (T)input;
}
}
Here is one way how you can do it. It's a bit complicated since we are going to implement it with labels and goto logic 😱
See my comments in the code below.
public static class MyTypeBuilder
{
public static void CompileAssembly(Field[] fields)
{
const string typeSignature = "MyDynamicType";
var assemblyName = new AssemblyName(typeSignature);
var assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule", $"{typeSignature}.dll");
CompileResultType(moduleBuilder, typeof(IDynamicObject), fields);
// save to review the compiled assembly
assemblyBuilder.Save($"{typeSignature}.dll");
}
private static Type CompileResultType(ModuleBuilder moduleBuilder, Type interfaceType, Field[] fields)
{
var typeBuilder = moduleBuilder.DefineType(moduleBuilder.Assembly.GetName().Name,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass |
TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,
null, new[] { interfaceType });
// T CastObject<T>(object input)
var castObject = typeBuilder.DefineMethod("CastObject",
MethodAttributes.Public,
null, new[] { typeof(object) });
{
var castObjectOutputParameter = castObject.DefineGenericParameters("T")[0];
castObject.SetReturnType(castObjectOutputParameter);
castObject.DefineParameter(1, ParameterAttributes.None, "input");
var il = castObject.GetILGenerator();
il.DeclareLocal(castObjectOutputParameter);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ret);
}
// create properties in advance so we can reference them later
var properties = fields.ToDictionary(
key => key.FieldName,
value => CreateProperty(typeBuilder, value.FieldName, value.FieldType)
);
// T GetProperty<T>(string propertyName)
var getProperty = typeBuilder.DefineMethod("GetProperty",
MethodAttributes.Public | MethodAttributes.Final |
MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
null, new[] { typeof(string) });
{
// define generic parameter T
var outputParameter = getProperty.DefineGenericParameters("T")[0];
getProperty.SetReturnType(outputParameter);
// define name for the propertyName parameter
getProperty.DefineParameter(1, ParameterAttributes.None, "propertyName");
// reference to "operator ==" to compare a field name with the propertyName value
var stringEquals =
typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public) ??
throw new InvalidOperationException();
var il = getProperty.GetILGenerator();
// declare local variables
il.DeclareLocal(typeof(string)); // loc_0 to store input for switch / case
il.DeclareLocal(outputParameter); // loc_1 to store result of the CastObject() call
// define general labels, we will mark their code locations later on
var returnLabel = il.DefineLabel(); // "return label"
var throwLabel = il.DefineLabel(); // "throw label" for throwing ArgumentException
// define "value labels" for each case body,
// use map to reference them later
var returnValueLabels = fields.ToDictionary(
key => key.FieldName,
value => il.DefineLabel()
);
// store propertyName in loc_0
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stloc_0);
foreach (var field in fields)
{
// check if propertyName == field.FieldName
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldstr, field.FieldName);
il.Emit(OpCodes.Call, stringEquals);
// if true, jump to the corresponding "return value" label
// we will mark a code location with it later (see next loop),
// right now we only need a reference
il.Emit(OpCodes.Brtrue, returnValueLabels[field.FieldName]);
}
// if we are here, that means the propertyName is unknown
// jump to the "throw label" location
il.Emit(OpCodes.Br, throwLabel);
foreach (var field in fields)
{
// mark the code with the corresponding "return value" label
il.MarkLabel(returnValueLabels[field.FieldName]);
// find a property we created before
// and pass its getter to the CastObject<T>() call
var property = properties[field.FieldName];
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, property.GetMethod);
il.Emit(OpCodes.Call, castObject);
// store result in loc_1
il.Emit(OpCodes.Stloc_1);
// jump to "return label"
il.Emit(OpCodes.Br, returnLabel);
}
// mark the following code that throws with "throw label"
il.MarkLabel(throwLabel);
// find ArgumentException(string) ctor
var argumentException =
typeof(ArgumentException).GetConstructor(new[] { typeof(string) }) ??
throw new InvalidOperationException();
// construct exception and throw
il.Emit(OpCodes.Ldstr, "propertyName");
il.Emit(OpCodes.Newobj, argumentException);
il.Emit(OpCodes.Throw);
// mark the following code with "return label"
il.MarkLabel(returnLabel);
// load value from loc_1
il.Emit(OpCodes.Ldloc_1);
// return
il.Emit(OpCodes.Ret);
}
// void SetProperty(string propertyName, object value)
// logic is very similar to GetProperty
var setProperty = typeBuilder.DefineMethod("SetProperty",
MethodAttributes.Public | MethodAttributes.Final |
MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
null, new[] { typeof(string), typeof(object) });
{
setProperty.DefineParameter(1, ParameterAttributes.None, "propertyName");
setProperty.DefineParameter(2, ParameterAttributes.None, "value");
var stringEquals =
typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public) ??
throw new InvalidOperationException();
var il = setProperty.GetILGenerator();
il.DeclareLocal(typeof(string));
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stloc_0);
var returnLabel = il.DefineLabel();
var throwLabel = il.DefineLabel();
var setValueLabels = fields.ToDictionary(
key => key.FieldName,
value => il.DefineLabel()
);
foreach (var field in fields)
{
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldstr, field.FieldName);
il.Emit(OpCodes.Call, stringEquals);
il.Emit(OpCodes.Brtrue, setValueLabels[field.FieldName]);
}
il.Emit(OpCodes.Br, throwLabel);
foreach (var field in fields)
{
var property = properties[field.FieldName];
il.MarkLabel(setValueLabels[field.FieldName]);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Castclass, field.FieldType);
il.Emit(OpCodes.Call, property.SetMethod);
il.Emit(OpCodes.Br, returnLabel);
}
il.MarkLabel(throwLabel);
var argumentException =
typeof(ArgumentException).GetConstructor(new[] { typeof(string) }) ??
throw new InvalidOperationException();
il.Emit(OpCodes.Ldstr, "propertyName");
il.Emit(OpCodes.Newobj, argumentException);
il.Emit(OpCodes.Throw);
il.MarkLabel(returnLabel);
il.Emit(OpCodes.Ret);
}
typeBuilder.DefineDefaultConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName
);
return typeBuilder.CreateType();
}
private static PropertyBuilder 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);
return propertyBuilder;
}
}
Here is how it works
var fields = new[]
{
new Field { FieldName = "Str1", FieldType = typeof(string) },
new Field { FieldName = "Str2", FieldType = typeof(string) },
new Field { FieldName = "Str3", FieldType = typeof(string) }
};
MyTypeBuilder.CompileAssembly(fields);
...will generate the following:
public class MyDynamicType : IDynamicObject
{
// ... getters and setters
public T CastObject<T>(object input)
{
return (T)input;
}
public T GetProperty<T>(string propertyName)
{
switch (propertyName)
{
case "Str1":
return CastObject<T>(this.Str1);
case "Str2":
return CastObject<T>(this.Str2);
case "Str3":
return CastObject<T>(this.Str3);
default:
throw new ArgumentException("propertyName");
}
}
public void SetProperty(string propertyName, object value)
{
switch (propertyName)
{
case "Str1":
Str1 = (string)value;
break;
case "Str2":
Str2 = (string)value;
break;
case "Str3":
Str3 = (string)value;
break;
default:
throw new ArgumentException("propertyName");
}
}
}

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

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

How to call a method on a field with ILGenerator.Emit?

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;
}
}

Categories

Resources