First, and to make things clearer I'll explain my scenario from the top:
I have a method which has the following signature:
public virtual void SendEmail(String from, List<String> recepients, Object model)
What I want to do is generate an anonymous object which has the properties of the model object along with the first two parameters as well. Flattening the model object into a PropertyInfo[] is very straightforward. Accordingly, I thought of creating a Dictionary which would hold the PropertyInfo's and the first two params, and then be converted into the anonymous object where the key is the name of the property and the value is the actual value of the property.
Is that possible? Any other suggestions?
If you really want to convert the dictionary to an object that has the items of the dictionary as properties, you can use ExpandoObject:
var dict = new Dictionary<string, object> { { "Property", "foo" } };
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;
foreach (var kvp in dict)
{
eoColl.Add(kvp);
}
dynamic eoDynamic = eo;
string value = eoDynamic.Property;
I tried to do this in one statement with a reduce function (Aggregate in Linq). The code below does the same as the accepted answer:
var dict = new Dictionary<string, object> { { "Property", "foo" } };
dynamic eo = dict.Aggregate(new ExpandoObject() as IDictionary<string, Object>,
(a, p) => { a.Add(p); return a; });
string value = eo.Property;
If you want to convert Dictionary<string, object> To Anonymous System.Object. You can use this method:
public static object FromDictToAnonymousObj<TValue>(IDictionary<string, TValue> dict)
{
var types = new Type[dict.Count];
for (int i = 0; i < types.Length; i++)
{
types[i] = typeof(TValue);
}
// dictionaries don't have an order, so we force an order based
// on the Key
var ordered = dict.OrderBy(x => x.Key).ToArray();
string[] names = Array.ConvertAll(ordered, x => x.Key);
Type type = AnonymousType.CreateType(types, names);
object[] values = Array.ConvertAll(ordered, x => (object)x.Value);
object obj = type.GetConstructor(types).Invoke(values);
return obj;
}
like this:
var dict = new Dictionary<string, string>
{
{"Id", "1"},
{"Title", "My title"},
{"Description", "Blah blah blah"},
};
object obj1 = FromDictToAnonymousObj(dict);
to obtain your object.
Where AnonymousType class code is:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
/// <summary>
/// The code generated should be nearly equal to the one generated by
/// csc 12.0.31101.0 when compiling with /optimize+ /debug-. The main
/// difference is in the GetHashCode() (the base init_hash used is
/// compiler-dependant) and in the maxstack of the generated methods.
/// Note that Roslyn (at least the one present at
/// tryroslyn.azurewebsites.net) generates different code for anonymous
/// types.
/// </summary>
public static class AnonymousType
{
private static readonly ConcurrentDictionary<string, Type> GeneratedTypes = new ConcurrentDictionary<string, Type>();
private static readonly AssemblyBuilder AssemblyBuilder;
private static readonly ModuleBuilder ModuleBuilder;
private static readonly string FileName;
// Some objects we cache
private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never });
private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
private static readonly ConstructorInfo StringBuilderCtor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null);
private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null);
private static readonly Type EqualityComparer = typeof(EqualityComparer<>);
private static readonly Type EqualityComparerGenericArgument = EqualityComparer.GetGenericArguments()[0];
private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null);
private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null);
private static int Index = -1;
static AnonymousType()
{
var assemblyName = new AssemblyName("AnonymousTypes");
FileName = assemblyName.Name + ".dll";
AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder = AssemblyBuilder.DefineDynamicModule("AnonymousTypes", FileName);
}
public static void Dump()
{
AssemblyBuilder.Save(FileName);
}
/// <summary>
///
/// </summary>
/// <param name="types"></param>
/// <param name="names"></param>
/// <returns></returns>
public static Type CreateType(Type[] types, string[] names)
{
if (types == null)
{
throw new ArgumentNullException("types");
}
if (names == null)
{
throw new ArgumentNullException("names");
}
if (types.Length != names.Length)
{
throw new ArgumentException("names");
}
// Anonymous classes are generics based. The generic classes
// are distinguished by number of parameters and name of
// parameters. The specific types of the parameters are the
// generic arguments. We recreate this by creating a fullName
// composed of all the property names, separated by a "|"
string fullName = string.Join("|", names.Select(x => Escape(x)));
Type type;
if (!GeneratedTypes.TryGetValue(fullName, out type))
{
// We create only a single class at a time, through this lock
// Note that this is a variant of the double-checked locking.
// It is safe because we are using a thread safe class.
lock (GeneratedTypes)
{
if (!GeneratedTypes.TryGetValue(fullName, out type))
{
int index = Interlocked.Increment(ref Index);
string name = names.Length != 0 ? string.Format("<>f__AnonymousType{0}`{1}", index, names.Length) : string.Format("<>f__AnonymousType{0}", index);
TypeBuilder tb = ModuleBuilder.DefineType(name, TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.AutoLayout | TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
tb.SetCustomAttribute(CompilerGeneratedAttributeBuilder);
GenericTypeParameterBuilder[] generics = null;
if (names.Length != 0)
{
string[] genericNames = Array.ConvertAll(names, x => string.Format("<{0}>j__TPar", x));
generics = tb.DefineGenericParameters(genericNames);
}
else
{
generics = new GenericTypeParameterBuilder[0];
}
// .ctor
ConstructorBuilder constructor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, generics);
constructor.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
ILGenerator ilgeneratorConstructor = constructor.GetILGenerator();
ilgeneratorConstructor.Emit(OpCodes.Ldarg_0);
ilgeneratorConstructor.Emit(OpCodes.Call, ObjectCtor);
var fields = new FieldBuilder[names.Length];
// There are two for cycles because we want to have
// all the getter methods before all the other
// methods
for (int i = 0; i < names.Length; i++)
{
// field
fields[i] = tb.DefineField(string.Format("<{0}>i__Field", names[i]), generics[i], FieldAttributes.Private | FieldAttributes.InitOnly);
fields[i].SetCustomAttribute(DebuggerBrowsableAttributeBuilder);
// .ctor
constructor.DefineParameter(i + 1, ParameterAttributes.None, names[i]);
ilgeneratorConstructor.Emit(OpCodes.Ldarg_0);
if (i == 0)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_1);
}
else if (i == 1)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_2);
}
else if (i == 2)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_3);
}
else if (i < 255)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_S, (byte)(i + 1));
}
else
{
// Ldarg uses a ushort, but the Emit only
// accepts short, so we use a unchecked(...),
// cast to short and let the CLR interpret it
// as ushort
ilgeneratorConstructor.Emit(OpCodes.Ldarg, unchecked((short)(i + 1)));
}
ilgeneratorConstructor.Emit(OpCodes.Stfld, fields[i]);
// getter
MethodBuilder getter = tb.DefineMethod(string.Format("get_{0}", names[i]), MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, CallingConventions.HasThis, generics[i], Type.EmptyTypes);
ILGenerator ilgeneratorGetter = getter.GetILGenerator();
ilgeneratorGetter.Emit(OpCodes.Ldarg_0);
ilgeneratorGetter.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorGetter.Emit(OpCodes.Ret);
PropertyBuilder property = tb.DefineProperty(names[i], PropertyAttributes.None, CallingConventions.HasThis, generics[i], Type.EmptyTypes);
property.SetGetMethod(getter);
}
// ToString()
MethodBuilder toString = tb.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(string), Type.EmptyTypes);
toString.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
ILGenerator ilgeneratorToString = toString.GetILGenerator();
ilgeneratorToString.DeclareLocal(typeof(StringBuilder));
ilgeneratorToString.Emit(OpCodes.Newobj, StringBuilderCtor);
ilgeneratorToString.Emit(OpCodes.Stloc_0);
// Equals
MethodBuilder equals = tb.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(bool), new[] { typeof(object) });
equals.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
equals.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator ilgeneratorEquals = equals.GetILGenerator();
ilgeneratorEquals.DeclareLocal(tb);
ilgeneratorEquals.Emit(OpCodes.Ldarg_1);
ilgeneratorEquals.Emit(OpCodes.Isinst, tb);
ilgeneratorEquals.Emit(OpCodes.Stloc_0);
ilgeneratorEquals.Emit(OpCodes.Ldloc_0);
Label equalsLabel = ilgeneratorEquals.DefineLabel();
// GetHashCode()
MethodBuilder getHashCode = tb.DefineMethod("GetHashCode", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(int), Type.EmptyTypes);
getHashCode.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
ILGenerator ilgeneratorGetHashCode = getHashCode.GetILGenerator();
ilgeneratorGetHashCode.DeclareLocal(typeof(int));
if (names.Length == 0)
{
ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4_0);
}
else
{
// As done by Roslyn
// Note that initHash can vary, because
// string.GetHashCode() isn't "stable" for
// different compilation of the code
int initHash = 0;
for (int i = 0; i < names.Length; i++)
{
initHash = unchecked(initHash * (-1521134295) + fields[i].Name.GetHashCode());
}
// Note that the CSC seems to generate a
// different seed for every anonymous class
ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4, initHash);
}
for (int i = 0; i < names.Length; i++)
{
// Equals()
Type equalityComparerT = EqualityComparer.MakeGenericType(generics[i]);
MethodInfo equalityComparerTDefault = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerDefault);
MethodInfo equalityComparerTEquals = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerEquals);
ilgeneratorEquals.Emit(OpCodes.Brfalse_S, equalsLabel);
ilgeneratorEquals.Emit(OpCodes.Call, equalityComparerTDefault);
ilgeneratorEquals.Emit(OpCodes.Ldarg_0);
ilgeneratorEquals.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorEquals.Emit(OpCodes.Ldloc_0);
ilgeneratorEquals.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorEquals.Emit(OpCodes.Callvirt, equalityComparerTEquals);
// GetHashCode();
MethodInfo EqualityComparerTGetHashCode = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerGetHashCode);
ilgeneratorGetHashCode.Emit(OpCodes.Stloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4, -1521134295);
ilgeneratorGetHashCode.Emit(OpCodes.Ldloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Mul);
ilgeneratorGetHashCode.Emit(OpCodes.Call, EqualityComparerDefault);
ilgeneratorGetHashCode.Emit(OpCodes.Ldarg_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorGetHashCode.Emit(OpCodes.Callvirt, EqualityComparerGetHashCode);
ilgeneratorGetHashCode.Emit(OpCodes.Add);
// ToString()
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Ldstr, i == 0 ? string.Format("{{ {0} = ", names[i]) : string.Format(", {0} = ", names[i]));
ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendString);
ilgeneratorToString.Emit(OpCodes.Pop);
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Ldarg_0);
ilgeneratorToString.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorToString.Emit(OpCodes.Box, generics[i]);
ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendObject);
ilgeneratorToString.Emit(OpCodes.Pop);
}
// .ctor
ilgeneratorConstructor.Emit(OpCodes.Ret);
// Equals()
if (names.Length == 0)
{
ilgeneratorEquals.Emit(OpCodes.Ldnull);
ilgeneratorEquals.Emit(OpCodes.Ceq);
ilgeneratorEquals.Emit(OpCodes.Ldc_I4_0);
ilgeneratorEquals.Emit(OpCodes.Ceq);
}
else
{
ilgeneratorEquals.Emit(OpCodes.Ret);
ilgeneratorEquals.MarkLabel(equalsLabel);
ilgeneratorEquals.Emit(OpCodes.Ldc_I4_0);
}
ilgeneratorEquals.Emit(OpCodes.Ret);
// GetHashCode()
ilgeneratorGetHashCode.Emit(OpCodes.Stloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ldloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ret);
// ToString()
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Ldstr, names.Length == 0 ? "{ }" : " }");
ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendString);
ilgeneratorToString.Emit(OpCodes.Pop);
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Callvirt, ObjectToString);
ilgeneratorToString.Emit(OpCodes.Ret);
type = tb.CreateType();
type = GeneratedTypes.GetOrAdd(fullName, type);
}
}
}
if (types.Length != 0)
{
type = type.MakeGenericType(types);
}
return type;
}
private static string Escape(string str)
{
// We escape the \ with \\, so that we can safely escape the
// "|" (that we use as a separator) with "\|"
str = str.Replace(#"\", #"\\");
str = str.Replace(#"|", #"\|");
return str;
}
}
Reference: https://stackoverflow.com/a/29428640/2073920
If you have a class you want to covert the dictionary too, you can use the following to convert a dictionary to an object of that class:
Example class:
public class Properties1
{
public string Property { get; set; }
}
The solution:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, object> dict = new Dictionary<string, object> { { "Property", "foo" } };
Properties1 properties = serializer.ConvertToType<Properties1>(dict);
string value = properties.Property;
You could also use a method like this to build the object from the dictionary, obviously this also requires you to have a class.
private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
{
T t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (!dict.Any(x => x.Key.Equals(property.Name,
StringComparison.InvariantCultureIgnoreCase)))
continue;
KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name,
StringComparison.InvariantCultureIgnoreCase));
Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
object newA = Convert.ChangeType(item.Value, newT);
t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
}
return t;
}
However if you do not have the class you can create a dynamic object from a dictionary like this:
private static dynamic DictionaryToObject(Dictionary<string, object> dict)
{
IDictionary<string, object> eo = (IDictionary<string, object>)new ExpandoObject();
foreach (KeyValuePair<string, object> kvp in dict)
{
eo.Add(kvp);
}
return eo;
}
You can use it like this:
Dictionary<string, object> dict = new Dictionary<string, object> {{ "Property", "foo" }};
dynamic properties = DictionaryToObject(dict);
string value = properties.Property;
Slightly more modular version of svick's answer, using a couple extension methods:
public static class Extensions
{
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}
public static dynamic ToDynamicObject(this IDictionary<string, object> source)
{
ICollection<KeyValuePair<string, object>> someObject = new ExpandoObject();
someObject.AddRange(source);
return someObject;
}
}
The code below handles sub-dictionaries and converts them to nested dynamic objects as well:
[return: NotNullIfNotNull(nameof(dictionary))]
static dynamic? ToDynamic(IReadOnlyDictionary<string, object?>? dictionary) =>
dictionary?.Aggregate(
(IDictionary<string, object?>)new ExpandoObject(),
(obj, i) =>
{
if (i.Value is IReadOnlyDictionary<string, object?> nestedDictionary)
obj.Add(new(i.Key, ToDynamic(nestedDictionary)));
else
obj.Add(i);
return obj;
});
This approach allows you to access the contents of nested dictionaries just by accessing the dynamic object itself:
var record = ToDynamic(...);
string cityName = record.city.name;
Anonymous objects are one that generated for you by compiler. You cannot generate dynamically create one. On the other hand you can emit such object, but I really do not think this is good idea.
May be you can try dynamic objects? The result will be an object with all properties you need.
The credit here goes to the accepted answer. Adding this because I wanted to turn a List< Dictionary< string,object >> into a List< dynamic>. The purpose is for pulling records from a database table. Here is what I did.
public static List<dynamic> ListDictionaryToListDynamic(List<Dictionary<string,object>> dbRecords)
{
var eRecords = new List<dynamic>();
foreach (var record in dbRecords)
{
var eRecord = new ExpandoObject() as IDictionary<string, object>;
foreach (var kvp in record)
{
eRecord.Add(kvp);
}
eRecords.Add(eRecord);
}
return eRecords;
}
Related
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);
}
}
In C# 3.0 you can create anonymous class with the following syntax
var o1 = new { Id = 1, Name = "Foo" };
Is there a way to dynamic create these anonymous class to a variable?
Example:
var o1 = new { Id = 1, Name = "Foo" };
var o2 = new { SQ = 2, Birth = DateTime.Now };
Dynamic create Example:
var o1 = DynamicNewAnonymous(new NameValuePair("Id", 1), new NameValuePair("Name", "Foo"));
var o2 = DynamicNewAnonymous(new NameValuePair("SQ", 2), new NameValuePair("Birth",
DateTime.Now));
Beacuse I need to do:
dynamic o1 = new ExpandObject();
o1."ID" = 1; <--"ID" is dynamic name
o1."Name" = "Foo"; <--"Name" is dynamic name
And Scene1:
void ShowPropertiesValue(object o)
{
Type oType = o.GetType();
foreach(var pi in oType.GetProperties())
{
Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
}
}
if I call:
dynamic o1 = new ExpandObject();
o1.Name = "123";
ShowPropertiesValue(o1);
It can't show the result:
Name = 123
And also I how to Convert the ExpandoObject to AnonymouseType ?
Type type = o1.GetType();
type.GetProperties(); <--I hope it can get all property of o1
Last, I modify ShowPropertiesValue() method
void ShowPropertiesValue(object o)
{
if( o is static object ) <--How to check it is dynamic or static object?
{
Type oType = o.GetType();
foreach(var pi in oType.GetProperties())
{
Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
}
}
else if( o is dynamic object ) <--How to check it is dynamic or static object?
{
foreach(var pi in ??? ) <--How to get common dynamic object's properties info ?
{
Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
}
}
}
How to implement DynamicNewAnonymous method or how to modify the ShowPropertiesValue()?
My motivations is:
dynamic o1 = new MyDynamic();
o1.Name = "abc";
Type o1Type = o1.GetType();
var props = o1Type.GetProperties(); <--I hope can get the Name Property
If i can hook dynamicObject's GetType Method, and Compel convert to strongly-typed Type.
The above Seamless code can work fine.
Anonymous types are just regular types that are implicitly declared. They have little to do with dynamic.
Now, if you were to use an ExpandoObject and reference it through a dynamic variable, you could add or remove fields on the fly.
edit
Sure you can: just cast it to IDictionary<string, object>. Then you can use the indexer.
You use the same casting technique to iterate over the fields:
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
foreach (var property in (IDictionary<string, object>)employee)
{
Console.WriteLine(property.Key + ": " + property.Value);
}
// This code example produces the following output:
// Name: John Smith
// Age: 33
The above code and more can be found by clicking on that link.
You can create an ExpandoObject like this:
IDictionary<string,object> expando = new ExpandoObject();
expando["Name"] = value;
And after casting it to dynamic, those values will look like properties:
dynamic d = expando;
Console.WriteLine(d.Name);
However, they are not actual properties and cannot be accessed using Reflection. So the following statement will return a null:
d.GetType().GetProperty("Name")
Of cause it's possible to create dynamic classes using very cool ExpandoObject class.
But recently I worked on project and faced that Expando Object is serealized in not the same format on xml as an simple Anonymous class, it was pity =( , that is why I decided to create my own class and share it with you. It's using reflection and dynamic directive , builds Assembly, Class and Instance truly dynamicly. You can add, remove and change properties that is included in your class on fly
Here it is :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using static YourNamespace.DynamicTypeBuilderTest;
namespace YourNamespace
{
/// This class builds Dynamic Anonymous Classes
public class DynamicTypeBuilderTest
{
///
/// Create instance based on any Source class as example based on PersonalData
///
public static object CreateAnonymousDynamicInstance(PersonalData personalData, Type dynamicType, List<ClassDescriptorKeyValue> classDescriptionList)
{
var obj = Activator.CreateInstance(dynamicType);
var propInfos = dynamicType.GetProperties();
classDescriptionList.ForEach(x => SetValueToProperty(obj, propInfos, personalData, x));
return obj;
}
private static void SetValueToProperty(object obj, PropertyInfo[] propInfos, PersonalData aisMessage, ClassDescriptorKeyValue description)
{
propInfos.SingleOrDefault(x => x.Name == description.Name)?.SetValue(obj, description.ValueGetter(aisMessage), null);
}
public static dynamic CreateAnonymousDynamicType(string entityName, List<ClassDescriptorKeyValue> classDescriptionList)
{
AssemblyName asmName = new AssemblyName();
asmName.Name = $"{entityName}Assembly";
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule($"{asmName.Name}Module");
TypeBuilder typeBuilder = moduleBuilder.DefineType($"{entityName}Dynamic", TypeAttributes.Public);
classDescriptionList.ForEach(x => CreateDynamicProperty(typeBuilder, x));
return typeBuilder.CreateTypeInfo().AsType();
}
private static void CreateDynamicProperty(TypeBuilder typeBuilder, ClassDescriptorKeyValue description)
{
CreateDynamicProperty(typeBuilder, description.Name, description.Type);
}
///
///Creation Dynamic property (from MSDN) with some Magic
///
public static void CreateDynamicProperty(TypeBuilder typeBuilder, string name, Type propType)
{
FieldBuilder fieldBuider = typeBuilder.DefineField($"{name.ToLower()}Field",
propType,
FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name,
PropertyAttributes.HasDefault,
propType,
null);
MethodAttributes getSetAttr =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
MethodBuilder methodGetBuilder =
typeBuilder.DefineMethod($"get_{name}",
getSetAttr,
propType,
Type.EmptyTypes);
ILGenerator methodGetIL = methodGetBuilder.GetILGenerator();
methodGetIL.Emit(OpCodes.Ldarg_0);
methodGetIL.Emit(OpCodes.Ldfld, fieldBuider);
methodGetIL.Emit(OpCodes.Ret);
MethodBuilder methodSetBuilder =
typeBuilder.DefineMethod($"set_{name}",
getSetAttr,
null,
new Type[] { propType });
ILGenerator methodSetIL = methodSetBuilder.GetILGenerator();
methodSetIL.Emit(OpCodes.Ldarg_0);
methodSetIL.Emit(OpCodes.Ldarg_1);
methodSetIL.Emit(OpCodes.Stfld, fieldBuider);
methodSetIL.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(methodGetBuilder);
propertyBuilder.SetSetMethod(methodSetBuilder);
}
public class ClassDescriptorKeyValue
{
public ClassDescriptorKeyValue(string name, Type type, Func<PersonalData, object> valueGetter)
{
Name = name;
ValueGetter = valueGetter;
Type = type;
}
public string Name;
public Type Type;
public Func<PersonalData, object> ValueGetter;
}
///
///Your Custom class description based on any source class for example
/// PersonalData
public static IEnumerable<ClassDescriptorKeyValue> GetAnonymousClassDescription(bool includeAddress, bool includeFacebook)
{
yield return new ClassDescriptorKeyValue("Id", typeof(string), x => x.Id);
yield return new ClassDescriptorKeyValue("Name", typeof(string), x => x.FirstName);
yield return new ClassDescriptorKeyValue("Surname", typeof(string), x => x.LastName);
yield return new ClassDescriptorKeyValue("Country", typeof(string), x => x.Country);
yield return new ClassDescriptorKeyValue("Age", typeof(int?), x => x.Age);
yield return new ClassDescriptorKeyValue("IsChild", typeof(bool), x => x.Age < 21);
if (includeAddress)
yield return new ClassDescriptorKeyValue("Address", typeof(string), x => x?.Contacts["Address"]);
if (includeFacebook)
yield return new ClassDescriptorKeyValue("Facebook", typeof(string), x => x?.Contacts["Facebook"]);
}
///
///Source Data Class for example
/// of cause you can use any other class
public class PersonalData
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country { get; set; }
public int Age { get; set; }
public Dictionary<string, string> Contacts { get; set; }
}
}
}
It is also very simple to use DynamicTypeBuilder, you just need put few lines like this:
public class ExampleOfUse
{
private readonly bool includeAddress;
private readonly bool includeFacebook;
private readonly dynamic dynamicType;
private readonly List<ClassDescriptorKeyValue> classDiscriptionList;
public ExampleOfUse(bool includeAddress = false, bool includeFacebook = false)
{
this.includeAddress = includeAddress;
this.includeFacebook = includeFacebook;
this.classDiscriptionList = DynamicTypeBuilderTest.GetAnonymousClassDescription(includeAddress, includeFacebook).ToList();
this.dynamicType = DynamicTypeBuilderTest.CreateAnonymousDynamicType("VeryPrivateData", this.classDiscriptionList);
}
public object Map(PersonalData privateInfo)
{
object dynamicObject = DynamicTypeBuilderTest.CreateAnonymousDynamicInstance(privateInfo, this.dynamicType, classDiscriptionList);
return dynamicObject;
}
}
I hope that this code snippet help somebody =) Enjoy!
I'm using an object factory for dynamically creating instances by interface with help of reflection.
My code:
public static class ObjectFactory
{
private static readonly ConcurrentDictionary<Type, Type> TypeCache = new ConcurrentDictionary<Type, Type>();
public static T CreateInstance<T>(Type parent = null)
{
if (!typeof(T).IsInterface) throw new ArgumentException($"Type {typeof(T).Name} must be an interface.");
var newType = TypeCache.GetOrAdd(typeof(T), t => BuildType(typeof(T), parent));
return (T)Activator.CreateInstance(newType);
}
private static Type BuildType(Type interfaceType, Type parent = null)
{
var assemblyName = new AssemblyName($"DynamicAssembly_{Guid.NewGuid():N}");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
var typeName = $"{RemoveInterfacePrefix(interfaceType.Name)}_{Guid.NewGuid():N}";
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
if (parent != null)
typeBuilder.SetParent(parent);
typeBuilder.AddInterfaceImplementation(interfaceType);
var properties = interfaceType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var methods = interfaceType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
BuildProperties(typeBuilder, properties);
BuildMethods(typeBuilder, methods);
return typeBuilder.CreateType();
string RemoveInterfacePrefix(string name) => Regex.Replace(name, "^I", string.Empty);
}
private static void BuildMethods(TypeBuilder typeBuilder, IEnumerable<MethodInfo> methods)
{
foreach (var method in methods)
{
var paramTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
AddMethodDynamically(typeBuilder, method.Name, paramTypes, method.ReturnType, "A");
}
}
private static void BuildProperties(TypeBuilder typeBuilder, IEnumerable<PropertyInfo> properties)
{
foreach (var property in properties)
{
BuildProperty(typeBuilder, property);
}
}
private static PropertyBuilder BuildProperty(TypeBuilder typeBuilder, PropertyInfo property)
{
var fieldName = $"<{property.Name}>k__BackingField";
var propertyBuilder = typeBuilder.DefineProperty(property.Name, System.Reflection.PropertyAttributes.None, property.PropertyType, Type.EmptyTypes);
// Build backing-field.
var fieldBuilder = typeBuilder.DefineField(fieldName, property.PropertyType, FieldAttributes.Private);
var getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
var getterBuilder = BuildGetter(typeBuilder, property, fieldBuilder, getSetAttributes);
var setterBuilder = BuildSetter(typeBuilder, property, fieldBuilder, getSetAttributes);
propertyBuilder.SetGetMethod(getterBuilder);
propertyBuilder.SetSetMethod(setterBuilder);
return propertyBuilder;
}
private static MethodBuilder BuildGetter(TypeBuilder typeBuilder, PropertyInfo property, FieldBuilder fieldBuilder, MethodAttributes attributes)
{
var getterBuilder = typeBuilder.DefineMethod($"get_{property.Name}", attributes, property.PropertyType, Type.EmptyTypes);
var ilGenerator = getterBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fieldBuilder);
if (property.GetCustomAttribute<NotNullAttribute>() != null)
{
// Build null check
ilGenerator.Emit(OpCodes.Dup);
var isFieldNull = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brtrue_S, isFieldNull);
ilGenerator.Emit(OpCodes.Pop);
ilGenerator.Emit(OpCodes.Ldstr, $"{property.Name} isn't set.");
var invalidOperationExceptionConstructor = typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) });
ilGenerator.Emit(OpCodes.Newobj, invalidOperationExceptionConstructor);
ilGenerator.Emit(OpCodes.Throw);
ilGenerator.MarkLabel(isFieldNull);
}
ilGenerator.Emit(OpCodes.Ret);
return getterBuilder;
}
private static void AddMethodDynamically(TypeBuilder myTypeBld,
string mthdName,
Type[] mthdParams,
Type returnType,
string mthdAction)
{
MethodBuilder myMthdBld = myTypeBld.DefineMethod(
mthdName,
MethodAttributes.Public,
returnType,
mthdParams);
ILGenerator ILout = myMthdBld.GetILGenerator();
int numParams = mthdParams.Length;
for (byte x = 0; x < numParams; x++)
{
ILout.Emit(OpCodes.Ldarg_S, x);
}
if (numParams > 1)
{
for (int y = 0; y < (numParams - 1); y++)
{
switch (mthdAction)
{
case "A":
ILout.Emit(OpCodes.Add);
break;
case "M":
ILout.Emit(OpCodes.Mul);
break;
default:
ILout.Emit(OpCodes.Add);
break;
}
}
}
ILout.Emit(OpCodes.Ret);
}
private static MethodBuilder BuildSetter(TypeBuilder typeBuilder, PropertyInfo property, FieldBuilder fieldBuilder, MethodAttributes attributes)
{
var setterBuilder = typeBuilder.DefineMethod($"set_{property.Name}", attributes, null, new Type[] { property.PropertyType });
var ilGenerator = setterBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
// Build null check
if (property.GetCustomAttribute<NotNullAttribute>() != null)
{
var isValueNull = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Dup);
ilGenerator.Emit(OpCodes.Brtrue_S, isValueNull);
ilGenerator.Emit(OpCodes.Pop);
ilGenerator.Emit(OpCodes.Ldstr, property.Name);
var argumentNullExceptionConstructor = typeof(ArgumentNullException).GetConstructor(new Type[] { typeof(string) });
ilGenerator.Emit(OpCodes.Newobj, argumentNullExceptionConstructor);
ilGenerator.Emit(OpCodes.Throw);
ilGenerator.MarkLabel(isValueNull);
}
ilGenerator.Emit(OpCodes.Stfld, fieldBuilder);
ilGenerator.Emit(OpCodes.Ret);
return setterBuilder;
}
}
Method BuildMethods isn't creating implementation method by interface.
Please help solve 2 problems:
Create implementation method by interface;
All created classes have parent classes and all methods on interface after implementation have only executed method by parent class/ for example
public class Parent
{
public T Get<T, Y>(string url, params object[] query) => httpClient.Get<T>(url, query);
public T Post<T, Y>(string url, params Y model) => httpClient.Post<T>(url, model);
}
Create interface:
public inteface IRest
{
[HttpGet("/api/user-ids")] List<string> GetUserIds(int count, int skip);
}
What I want in finally on create instance by interface, I got instance where method GetUserIds execute Get<T, Y> from parent class
var rest = ObjectFactory.CreateInstance<IRest>(typeof(Parent));
var userIds = rest.GetUserIds(10, 0);
I´m currently trying to create a "Mock" for an interface using Reflection.Emit.
Therefore I created a base class that I use for all dynamically generated mocks.
For properties in the interface I want to call a "Get" Method in the base class that returns the property value.
public class Mock
{
public static TIf Wrap<TIf>() where TIf : class
{
if (!typeof(TIf).IsInterface)
throw new Exception(typeof(TIf) + " is no interface");
var asmBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule("Mock", true);
var typename = "ImplOf" + typeof(TIf).Name.Replace(" ", "") + ".Mock";
var typeBuilder = modBuilder.DefineType(typename, TypeAttributes.Public, typeof(WrapperBase));
typeBuilder.AddInterfaceImplementation(typeof(TIf));
// methods
foreach (var meth in typeof(TIf).GetMethods())
{
var del = typeof(WrapperBase).GetMethod(meth.ReturnType != typeof(void) ? "TryCallMethod" : "TryCallMethodOneWay");
var mb = typeBuilder.DefineMethod(meth.Name, meth.Attributes ^ MethodAttributes.Abstract);
mb.SetParameters(meth.GetParameters().Select(p => p.ParameterType)?.ToArray());
mb.SetReturnType(meth.ReturnType);
var mbil = mb.GetILGenerator();
mbil.Emit(OpCodes.Ldarg_0);
mbil.Emit(OpCodes.Ldstr, meth.Name);
for (var i = 0; i < meth.GetParameters().Length; i++)
{
mbil.Emit(OpCodes.Ldarg, i + 1);
}
mbil.Emit(OpCodes.Call, del);
mbil.Emit(OpCodes.Ret);
}
// properties
foreach (var prop in typeof(TIf).GetProperties())
{
var propertyBuilder = typeBuilder.DefineProperty(prop.Name, prop.Attributes, prop.PropertyType, null);
if (prop.CanRead)
{
var getterDelegate = typeof(WrapperBase).GetMethod("TryGetProperty");
var getter = typeBuilder.DefineMethod("get_" + prop.Name, MethodAttributes.Public, prop.PropertyType, Type.EmptyTypes);
var gil = getter.GetILGenerator();
gil.Emit(OpCodes.Ldarg_0);
gil.Emit(OpCodes.Ldstr, prop.Name);
gil.Emit(OpCodes.Callvirt, getterDelegate);
gil.Emit(OpCodes.Castclass, prop.PropertyType);
gil.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getter);
}
if (prop.CanWrite)
{
var setterDelegate = typeof(WrapperBase).GetMethod("TrySetProperty");
var setter = typeBuilder.DefineMethod("set_" + prop.Name, MethodAttributes.Public, typeof(void), Type.EmptyTypes);
var sil = setter.GetILGenerator();
sil.Emit(OpCodes.Ldarg_0);
sil.Emit(OpCodes.Ldstr, prop.Name);
sil.Emit(OpCodes.Ldarg_1);
sil.Emit(OpCodes.Call, setterDelegate);
sil.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setter);
}
}
var retType = typeBuilder.CreateType();
return retType.GetConstructor(new Type[0]).Invoke(new object[0]) as TIf;
}
public abstract class WrapperBase
{
public event Func<string, object[], object> OnTryCallMethod;
public event Action<string, object[]> OnTryCallMethodOneWay;
public event Func<string, object> OnTryGetProperty;
public event Action<string, object> OnTrySetProperty;
/// <inheritdoc />
public object TryCallMethod(string name, object[] pars)
{
return OnTryCallMethod?.Invoke(name, pars);
}
/// <inheritdoc />
public void TryCallMethodOneWay(string name, object[] pars)
{
OnTryCallMethodOneWay?.Invoke(name, pars);
}
/// <inheritdoc />
public object TryGetProperty(string name)
{
return OnTryGetProperty?.Invoke(name);
}
/// <inheritdoc />
public void TrySetProperty(string name, object value)
{
OnTrySetProperty?.Invoke(name, value);
}
}
}
Unfortunately I always get an InvalidProgramException when trying to read a "mocked" property.
Setting the property (which will delegate the call also to some base class method) works fine, same for method calls.
For testing, I created a quite simple interface:
public interface ITest
{
void Show(string text);
string Text { get; set; }
}
Now I´m calling the mock like this:
var wrapped = Mock.Wrap<ITest>();
// ***************** works - EventHandler is called with correct parameters!
((Mock.WrapperBase)wrapped).OnTryCallMethodOneWay += (s, objects) => { };
wrapped.Show("sss");
// ***************** works - EventHandler is called with correct parameters!
wrapped.Text = "";
((Mock.WrapperBase)wrapped).OnTrySetProperty += (s, val) => { };
// ***************** does NOT work - getting InvalidProgramException
((Mock.WrapperBase)wrapped).OnTryGetProperty += s => "";
var t = wrapped.Text;
After a bit of debugging, I've found your issue. I noticed that
wrapped.Text = "" was stepping into TryCallMethodOneWay when it's clearly written as calling TrySetProperty.
This is because foreach (var meth in typeof(TIf).GetMethods()) is going to return you getter and setter methods. That is; you're defining the getters and setters twice.
This is solved by a simple check:
var properties = typeof(TIf).GetProperties();
var propertyMethods = properties.SelectMany(p => new[] { p.GetGetMethod(), p.GetSetMethod() }).ToLookup(p => p);
foreach (var meth in typeof(TIf).GetMethods())
{
if (propertyMethods.Contains(meth))
continue;
...
}
Now, you also have to mark your implementing methods as Virtual if they're to implement an interface. So, you'll need to change the code to be the following:
var getter = typeBuilder.DefineMethod("get_" + prop.Name, MethodAttributes.Public | MethodAttributes.Virtual, prop.PropertyType, Type.EmptyTypes);
And
var setter = typeBuilder.DefineMethod("set_" + prop.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { prop.PropertyType });
And your code should work without issue
It is a long story ): I have some types look like this:
public class Model {
private readonly SomeType _member;
private readonly AnotherType _member2;
public Model(SomeType member, AnotherType member2) {
_member = member;
_member2 = member2;
}
public SomeType Member { get { return _member; } }
public AnotherType Member2 { get { return _member2; } }
}
I'm trying to create some expressions to create an instance of class, reads properties from some other objects (anon objects usually), and write the values to created instance's private fields -based on shown naming convention: Prop has field name: _prop.
I mean I want to write below objects to a new instance of Model:
var anon1 = new { Member = "something" };
// expected: new Model with _member = "something"
var anon2 = new { Member2 = "something" };
// expected: new Model with _member2 = "something"
var anon3 = new { Member = "something", Member2 = "something else" };
// expected: new Model with _member = "something" and _member2 = "something else"
I have created below code, it creates new instances, but do nothing with fields. Can you help me to find where I did wrong please?
public class InstanceCreator {
static public readonly Func<FieldInfo, PropertyInfo, bool> NamingConvention;
static InstanceCreator() {
NamingConvention = (f, p) => {
var startsWithUnderscope = f.Name.StartsWith("_");
var hasSameName = p.Name.Equals(f.Name.Remove(0, 1), StringComparison.OrdinalIgnoreCase);
var hasSameType = f.FieldType == p.PropertyType;
return startsWithUnderscope && hasSameName && hasSameType &&
f.IsInitOnly && !p.CanWrite;
};
}
private readonly Type _type;
private readonly Func<dynamic, dynamic> _creator;
public InstanceCreator(Type type) {
_type = type;
var ctor = GetCtor(type);
var propertyToFieldWriters = MakeWriters(type);
_creator = MakeCreator(type, ctor, propertyToFieldWriters);
}
private Expression GetCtor(Type type) {
if (type == typeof(string)) // ctor for string
return Expression.Lambda<Func<dynamic>>(
Expression.Constant(string.Empty));
if (type.IsValueType || // type has a parameterless ctor
type.GetConstructor(Type.EmptyTypes) != null)
return Expression.Lambda<Func<dynamic>>(Expression.New(type));
var info = typeof(FormatterServices).GetMethod("GetUninitializedObject");
var call = Expression.Call(info, Expression.Constant(type));
return call;
//return Expression.Lambda<Func<dynamic>>(call);
}
private IEnumerable<PropertyToFieldMapper> MakeWriters(Type type) {
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
var list = (from field in fields
let property = properties.FirstOrDefault(prop => NamingConvention(field, prop))
where property != null
select new PropertyToFieldMapper(field, property)).ToList();
foreach (var item in list) {
var sourceParameter = Expression.Parameter(type, "sourceParameter");
var propertyGetter = Expression.Property(sourceParameter, item.Property.Name);
var targetParameter = Expression.Parameter(type, "targetParameter");
var setterInfo = item.Field.GetType().GetMethod("SetValue", new[] { typeof(object), typeof(object) });
var setterCall = Expression.Call(Expression.Constant(item.Field), setterInfo,
new Expression[] {
Expression.Convert(targetParameter,typeof(object)),
Expression.Convert(propertyGetter,typeof(object))
});
var call = Expression.Lambda(setterCall, new[] { targetParameter, sourceParameter });
item.Call = call;
}
return list;
}
private Func<dynamic, dynamic> MakeCreator(
Type type, Expression ctor,
IEnumerable<PropertyToFieldMapper> writers) {
var list = new List<Expression>();
// creating new target
var targetVariable = Expression.Variable(type, "targetVariable");
list.Add(Expression.Assign(targetVariable, Expression.Convert(ctor, type)));
// find all properties in incoming data
var sourceParameter = Expression.Parameter(typeof(object), "sourceParameter");
var sourceTypeVariable = Expression.Variable(typeof(Type));
var sourceTypeGetter = Expression.Call(sourceParameter, "GetType", Type.EmptyTypes);
list.Add(Expression.Assign(sourceTypeVariable, sourceTypeGetter));
var sourcePropertiesVariable = Expression.Variable(typeof(PropertyInfo[]));
var sourcePropertiesGetter = Expression.Call(sourceTypeVariable, "GetProperties", Type.EmptyTypes);
list.Add(Expression.Assign(sourcePropertiesVariable, sourcePropertiesGetter));
// itrate over writers and add their Call to block
foreach (var writer in writers) {
var param = Expression.Parameter(typeof(PropertyInfo));
var prop = Expression.Property(param, "Name");
var eq = Expression.Equal(Expression.Constant(writer.Property.Name), prop);
var any = CallAny.Call(sourcePropertiesVariable, Expression.Lambda(eq, param));
var predicate = Expression.IfThen(any,
Expression.Lambda(writer.Call, new[] { targetVariable, sourceParameter }));
list.Add(predicate);
}
list.Add(targetVariable);
var block = Expression.Block(new[] { targetVariable, sourceTypeVariable, sourcePropertiesVariable }, list);
var lambda = Expression.Lambda<Func<dynamic, dynamic>>(
block, new[] { sourceParameter }
);
return lambda.Compile();
}
public dynamic Create(dynamic data) {
return _creator.Invoke(data);
}
private class PropertyToFieldMapper {
private readonly FieldInfo _field;
private readonly PropertyInfo _property;
public PropertyToFieldMapper(FieldInfo field, PropertyInfo property) {
_field = field;
_property = property;
}
public FieldInfo Field {
get { return _field; }
}
public PropertyInfo Property {
get { return _property; }
}
public Expression Call { get; set; }
}
}
Also, I have this CallAny class, created from here.
public class CallAny {
public static Expression Call(Expression collection, Expression predicate) {
Type cType = GetIEnumerableImpl(collection.Type);
collection = Expression.Convert(collection, cType);
Type elemType = cType.GetGenericArguments()[0];
Type predType = typeof(Func<,>).MakeGenericType(elemType, typeof(bool));
// Enumerable.Any<T>(IEnumerable<T>, Func<T,bool>)
var anyMethod = (MethodInfo)
GetGenericMethod(typeof(Enumerable), "Any", new[] { elemType },
new[] { cType, predType }, BindingFlags.Static);
return Expression.Call(anyMethod, collection, predicate);
}
static MethodBase GetGenericMethod(Type type, string name, Type[] typeArgs, Type[] argTypes, BindingFlags flags) {
int typeArity = typeArgs.Length;
var methods = type.GetMethods()
.Where(m => m.Name == name)
.Where(m => m.GetGenericArguments().Length == typeArity)
.Select(m => m.MakeGenericMethod(typeArgs));
return Type.DefaultBinder.SelectMethod(flags, methods.ToArray(), argTypes, null);
}
static Type GetIEnumerableImpl(Type type) {
// Get IEnumerable implementation. Either type is IEnumerable<T> for some T,
// or it implements IEnumerable<T> for some T. We need to find the interface.
if (IsIEnumerable(type))
return type;
Type[] t = type.FindInterfaces((m, o) => IsIEnumerable(m), null);
Debug.Assert(t.Length == 1);
return t[0];
}
static bool IsIEnumerable(Type type) {
return type.IsGenericType
&& type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}
}
And here is usage:
var inst = new InstanceCreator(typeof (Model)).Create(new {MyData});
Well, I found the problem. I should use ExpandoObject instead of dynamic keyword. And pass it to logic as IDictionary<string, object>. Here is the solution:
public class InstanceCreator {
static public readonly Func<FieldInfo, PropertyInfo, bool> NamingConvention;
static InstanceCreator() {
NamingConvention = (f, p) => {
var startsWithUnderscope = f.Name.StartsWith("_");
var hasSameName = p.Name.Equals(f.Name.Remove(0, 1), StringComparison.OrdinalIgnoreCase);
var hasSameType = f.FieldType == p.PropertyType;
return startsWithUnderscope && hasSameName && hasSameType &&
f.IsInitOnly && !p.CanWrite;
};
}
private readonly Type _type;
private readonly Func<IDictionary<string, object>, dynamic> _creator;
public InstanceCreator(Type type) {
_type = type;
var ctor = GetCtor(type);
var propertyToFieldMappers = MakeMappers(type);
_creator = MakeCreator(type, ctor, propertyToFieldMappers);
}
private Expression GetCtor(Type type) {
if (type == typeof(string)) // ctor for string
return Expression.Lambda<Func<dynamic>>(
Expression.Constant(string.Empty));
if (type.IsValueType || // type has a parameterless ctor
type.GetConstructor(Type.EmptyTypes) != null)
return Expression.Lambda<Func<dynamic>>(Expression.New(type));
var info = typeof(FormatterServices).GetMethod("GetUninitializedObject");
return Expression.Call(info, Expression.Constant(type));
}
private IEnumerable<PropertyToFieldMapper> MakeMappers(Type type) {
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
var list = from field in fields
let property = properties.FirstOrDefault(prop => NamingConvention(field, prop))
where property != null
select new PropertyToFieldMapper(field, property);
return list;
}
private Func<IDictionary<string, object>, dynamic> MakeCreator(
Type type, Expression ctor,
IEnumerable<PropertyToFieldMapper> maps) {
var list = new List<Expression>();
var vList = new List<ParameterExpression>();
// creating new target
var targetVariable = Expression.Variable(type, "targetVariable");
vList.Add(targetVariable);
list.Add(Expression.Assign(targetVariable, Expression.Convert(ctor, type)));
// accessing source
var sourceType = typeof(IDictionary<string, object>);
var sourceParameter = Expression.Parameter(sourceType, "sourceParameter");
// calling source ContainsKey(string) method
var containsKeyMethodInfo = sourceType.GetMethod("ContainsKey", new[] { typeof(string) });
var accessSourceIndexerProp = sourceType.GetProperty("Item");
var accessSourceIndexerInfo = accessSourceIndexerProp.GetGetMethod();
// itrate over writers and add their Call to block
var containsKeyMethodArgument = Expression.Variable(typeof(string), "containsKeyMethodArgument");
vList.Add(containsKeyMethodArgument);
foreach (var map in maps) {
list.Add(Expression.Assign(containsKeyMethodArgument, Expression.Constant(map.Property.Name)));
var containsKeyMethodCall = Expression.Call(sourceParameter, containsKeyMethodInfo,
new Expression[] { containsKeyMethodArgument });
// creating writer
var sourceValue = Expression.Call(sourceParameter, accessSourceIndexerInfo,
new Expression[] { containsKeyMethodArgument });
var setterInfo = map.Field.GetType().GetMethod("SetValue", new[] { typeof(object), typeof(object) });
var setterCall = Expression.Call(Expression.Constant(map.Field), setterInfo,
new Expression[] {
Expression.Convert(targetVariable,typeof(object)),
Expression.Convert(sourceValue,typeof(object))
});
list.Add(Expression.IfThen(containsKeyMethodCall, setterCall));
}
list.Add(targetVariable);
var block = Expression.Block(vList, list);
var lambda = Expression.Lambda<Func<IDictionary<string, object>, dynamic>>(
block, new[] { sourceParameter }
);
return lambda.Compile();
}
public dynamic Create(IDictionary<string, object> data) {
return _creator.Invoke(data);
}
private class PropertyToFieldMapper {
private readonly FieldInfo _field;
private readonly PropertyInfo _property;
public PropertyToFieldMapper(FieldInfo field, PropertyInfo property) {
_field = field;
_property = property;
}
public FieldInfo Field {
get { return _field; }
}
public PropertyInfo Property {
get { return _property; }
}
}
}