Expression tree to initialize new anonymous object with arbitrary number of properties - c#

I'm trying to use LINQ expression trees to initialize a new anonymous object with a subset of fields from a passed-in object. The subset of fields will typically be a single property but could be more (4 or so).
An example:
void DoWork(Type t)
{
//do some work to figure out which properties I want to use
List<PropertyInfo>() props = (from p in t.GetProperties()
where p.HasAttribute(MyAttribute)
select p).ToList();
//now I want to create a lambda expression that's like:
// (x=> new {x.Prop1, x.Prop2, ...})
//for each property in the list props
//create parameter
var param = Expression.Parameter(t,"t");
//get list of expressions for properties
var initValues = (from p in props
select Expression.PropertyOrField(param, p.Name)
).ToList();
//build expression body
Expression body = Expression. //<<<< I have no idea what to do here
//create lambda
dynamic propLambda = Expression.Lambda(body, param);
//use it! MyFunction( x=> new {x.Prop1, x.Prop2,...});
MyFunction(lambda);
}

The bad news: Since you're gonna build the anonymous type dynamically at runtime, it doesn't exist at compile time, as it would if the compiler encountered a new {...} in your code. There's no way around Reflection.Emit, which isn't tivial.
The good news: I've already done it, because I had the same needs. Used ILDASM to see what the compiler generates and mimic that as closely as possible.
So without further ado:
/// <summary>
/// Creates types that are much like anonymous types.
/// </summary>
public static class TupleFactory
{
// the dynamic module used to emit new types
private static readonly ModuleBuilder _module = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName { Name = nameof(TupleFactory) }, AssemblyBuilderAccess.Run).DefineDynamicModule(nameof(TupleFactory), false);
// the generic type definitions constructed so far
private static readonly Dictionary<ICollection<string>, Type> _genericTypeDefinitions = new Dictionary<ICollection<string>, Type>(CollectionComparer<string>.Default);
// the new expression factory singletons constructed so far
private static readonly Dictionary<ICollection<KeyValuePair<string, Type>>, ITupleFactory> _newExpressionFactories = new Dictionary<ICollection<KeyValuePair<string, Type>>, ITupleFactory>(new CollectionComparer<KeyValuePair<string, Type>>(KeyValueComparer<string, Type>.Default));
// some reflection objects used
private static readonly ConstructorInfo _objectCtor = typeof(object).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo _objectEquals = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(object) }, null);
private static readonly MethodInfo _objectGetHashCode = typeof(object).GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
private static readonly MethodInfo _objectToString = typeof(object).GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
private static readonly MethodInfo _stringFormat = typeof(string).GetMethod("Format", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string), typeof(object[]) }, null);
private static readonly MethodInfo _equalityComparerDefaultGetter;
private static readonly MethodInfo _equalityComparerEquals;
private static readonly MethodInfo _equalityComparerGetHashCode;
static TupleFactory()
{
// init more reflection objects
_equalityComparerDefaultGetter = typeof(EqualityComparer<>).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetGetMethod();
var eqT = typeof(EqualityComparer<>).GetGenericArguments()[0];
_equalityComparerEquals = typeof(EqualityComparer<>).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new[] { eqT, eqT }, null);
_equalityComparerGetHashCode = typeof(EqualityComparer<>).GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance, null, new[] { eqT }, null);
}
/// <summary>
/// Gets a <see cref="ITupleFactory"/> singleton for a sequence of properties.
/// </summary>
/// <param name="properties">Name/Type pairs for the properties.</param>
public static ITupleFactory Create(IEnumerable<KeyValuePair<string, Type>> properties)
{
// check input
if (properties == null) throw new ArgumentNullException(nameof(properties));
var propList = properties.ToList();
if (propList.Select(p => p.Key).Distinct().Count() != propList.Count)
throw new ArgumentException("Property names must be distinct.");
lock (_module) // locks access to the static dictionaries
{
ITupleFactory result;
if (_newExpressionFactories.TryGetValue(propList, out result)) // we already have it
return result;
var propertyNames = propList.Select(p => p.Key).ToList();
Type genericTypeDefinition;
if (!_genericTypeDefinitions.TryGetValue(propertyNames, out genericTypeDefinition))
{
#region create new generic type definition
{
var typeBuilder = _module.DefineType($"<>f__AnonymousType{_newExpressionFactories.Count}`{propertyNames.Count}", TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
var genParams = propertyNames.Count > 0
? typeBuilder.DefineGenericParameters(propertyNames.Select(p => $"<{p}>j__TPar").ToArray())
: new GenericTypeParameterBuilder[0];
// attributes on type
var debuggerDisplay = "\\{ " + string.Join(", ", propertyNames.Select(n => $"{n} = {{{n}}}")) + " }";
// ReSharper disable AssignNullToNotNullAttribute
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(DebuggerDisplayAttribute).GetConstructor(new[] { typeof(string) }), new object[] { debuggerDisplay }));
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
// ReSharper restore AssignNullToNotNullAttribute
var fields = new List<FieldBuilder>();
var props = new List<PropertyBuilder>();
foreach (var name in propertyNames)
{
var genParam = genParams[fields.Count];
var field = typeBuilder.DefineField($"<{name}>i__Field", genParam, FieldAttributes.Private | FieldAttributes.InitOnly);
fields.Add(field);
var property = typeBuilder.DefineProperty(name, PropertyAttributes.None, genParam, null);
props.Add(property);
var getter = typeBuilder.DefineMethod($"get_{name}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, genParam, Type.EmptyTypes);
var il = getter.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Ret);
property.SetGetMethod(getter);
}
#region ctor
{
// ReSharper disable once CoVariantArrayConversion
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, genParams);
var il = ctorBuilder.GetILGenerator();
// call base class ctor
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, _objectCtor);
// assign args to fields
for (var i = 0; i < fields.Count; i++)
{
il.Emit(OpCodes.Ldarg_0);
EmitLdarg(il, i + 1);
il.Emit(OpCodes.Stfld, fields[i]);
}
il.Emit(OpCodes.Ret);
}
#endregion
#region override Equals
{
var equals = typeBuilder.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(bool), new[] { typeof(object) });
typeBuilder.DefineMethodOverride(equals, _objectEquals);
var il = equals.GetILGenerator();
il.DeclareLocal(typeBuilder);
var retFalse = il.DefineLabel();
var ret = il.DefineLabel();
// local = argument as (the type being constructed)?
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Isinst, typeBuilder);
il.Emit(OpCodes.Stloc_0);
// push result of the "as" operator
il.Emit(OpCodes.Ldloc_0);
foreach (var field in fields)
{
var comparer = typeof(EqualityComparer<>).MakeGenericType(field.FieldType);
var defaultGetter = TypeBuilder.GetMethod(comparer, _equalityComparerDefaultGetter);
var equalsMethod = TypeBuilder.GetMethod(comparer, _equalityComparerEquals);
// check if the result of the previous check is false
il.Emit(OpCodes.Brfalse, retFalse);
// push EqualityComparer<FieldType>.Default.Equals(this.field, other.field)
il.Emit(OpCodes.Call, defaultGetter);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Callvirt, equalsMethod);
}
// jump to the end with what was the last result
il.Emit(OpCodes.Br_S, ret);
// push false
il.MarkLabel(retFalse);
il.Emit(OpCodes.Ldc_I4_0);
il.MarkLabel(ret);
il.Emit(OpCodes.Ret);
}
#endregion
#region override GetHashCode
{
var getHashCode = typeBuilder.DefineMethod("GetHashCode", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(int), Type.EmptyTypes);
typeBuilder.DefineMethodOverride(getHashCode, _objectGetHashCode);
var il = getHashCode.GetILGenerator();
// init result with seed
il.Emit(OpCodes.Ldc_I4, HashCode.Seed);
foreach (var field in fields)
{
var comparer = typeof(EqualityComparer<>).MakeGenericType(field.FieldType);
var defaultGetter = TypeBuilder.GetMethod(comparer, _equalityComparerDefaultGetter);
var getHashCodeMethod = TypeBuilder.GetMethod(comparer, _equalityComparerGetHashCode);
// hash so far * factor
il.Emit(OpCodes.Ldc_I4, HashCode.Factor);
il.Emit(OpCodes.Mul);
// ... + EqualityComparer<FieldType>.GetHashCode(field)
il.Emit(OpCodes.Call, defaultGetter);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Callvirt, getHashCodeMethod);
il.Emit(OpCodes.Add);
}
il.Emit(OpCodes.Ret);
}
#endregion
#region override ToString
{
var toString = typeBuilder.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(string), Type.EmptyTypes);
typeBuilder.DefineMethodOverride(toString, _objectToString);
var template = "{{ " + string.Join(", ", propertyNames.Select((n, i) => $"{n} = {{{i}}}")) + " }}";
var il = toString.GetILGenerator();
// push template
il.Emit(OpCodes.Ldstr, template);
// push new array
EmitLdc(il, fields.Count);
il.Emit(OpCodes.Newarr, typeof(object));
var index = 0;
foreach (var field in fields)
{
il.Emit(OpCodes.Dup); // duplicate array ref
EmitLdc(il, index); // push array index
// store boxed field in array
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Box, field.FieldType);
il.Emit(OpCodes.Stelem, typeof(object));
index++;
}
il.Emit(OpCodes.Call, _stringFormat);
il.Emit(OpCodes.Ret);
}
#endregion
genericTypeDefinition = typeBuilder.CreateType();
}
#endregion
_genericTypeDefinitions.Add(propertyNames, genericTypeDefinition);
}
var type = propList.Count == 0 ? genericTypeDefinition : genericTypeDefinition.MakeGenericType(propList.Select(p => p.Value).ToArray());
result = new TupleFactoryImpl(type, propertyNames);
_newExpressionFactories.Add(propList, result);
return result;
}
}
/// <summary>
/// Gets a <see cref="NewExpression"/> for a tuple type with the specified properties.
/// </summary>
public static NewExpression MakeNewExpression(IEnumerable<KeyValuePair<string, Expression>> properties)
{
var props = properties.ToList();
var tupleFactory = Create(props.Select(p => new KeyValuePair<string, Type>(p.Key, p.Value.Type)));
return tupleFactory.MakeNewExpression(props.Select(p => p.Value));
}
private sealed class TupleFactoryImpl : ITupleFactory
{
public Type TupleType { get; }
private readonly ConstructorInfo _ctor;
private readonly MemberInfo[] _properties;
public TupleFactoryImpl(Type tupleType, IEnumerable<string> propertyNames)
{
TupleType = tupleType;
_ctor = tupleType.GetConstructors().Single();
var propsByName = tupleType.GetProperties().ToDictionary(p => p.Name);
_properties = propertyNames.Select(name => (MemberInfo)propsByName[name]).ToArray();
}
public NewExpression MakeNewExpression(IEnumerable<Expression> arguments)
{
return Expression.New(_ctor, arguments, _properties);
}
}
/// <summary>
/// Helper function to pick the optimal op code.
/// </summary>
private static void EmitLdarg(ILGenerator il, int index)
{
if (index < 0) throw new ArgumentOutOfRangeException();
switch (index)
{
case 0: il.Emit(OpCodes.Ldarg_0); break;
case 1: il.Emit(OpCodes.Ldarg_1); break;
case 2: il.Emit(OpCodes.Ldarg_2); break;
case 3: il.Emit(OpCodes.Ldarg_3); break;
default:
if (index <= byte.MaxValue)
il.Emit(OpCodes.Ldarg_S, (byte)index);
else if (index <= short.MaxValue)
il.Emit(OpCodes.Ldarg, (short)index);
else
throw new ArgumentOutOfRangeException();
break;
}
}
/// <summary>
/// Helper function to pick the optimal op code.
/// </summary>
private static void EmitLdc(ILGenerator il, int i)
{
switch (i)
{
case -1: il.Emit(OpCodes.Ldc_I4_M1); break;
case 0: il.Emit(OpCodes.Ldc_I4_0); break;
case 1: il.Emit(OpCodes.Ldc_I4_1); break;
case 2: il.Emit(OpCodes.Ldc_I4_2); break;
case 3: il.Emit(OpCodes.Ldc_I4_3); break;
case 4: il.Emit(OpCodes.Ldc_I4_4); break;
case 5: il.Emit(OpCodes.Ldc_I4_5); break;
case 6: il.Emit(OpCodes.Ldc_I4_6); break;
case 7: il.Emit(OpCodes.Ldc_I4_7); break;
case 8: il.Emit(OpCodes.Ldc_I4_8); break;
default:
if (i >= byte.MinValue && i <= byte.MaxValue)
il.Emit(OpCodes.Ldc_I4_S, (byte)i);
else
il.Emit(OpCodes.Ldc_I4, i);
break;
}
}
}
/// <summary>
/// Compute a hash code.
/// </summary>
public struct HashCode
{
// magic numbers for hash code
public const int Seed = 0x20e699b;
public const int Factor = unchecked((int)0xa5555529);
private readonly int? _value;
private HashCode(int value)
{
_value = value;
}
/// <summary>
/// Convert to the actual hash code based on what was added so far.
/// </summary>
public static implicit operator int(HashCode hc) => hc._value ?? 0;
/// <summary>
/// Add a hash code to the state.
/// </summary>
/// <returns>An updated <see cref="HashCode"/>.</returns>
public static HashCode operator +(HashCode hc, int other) => new HashCode(unchecked((hc._value == null ? Seed : hc._value.Value * Factor) + other));
/// <summary>
/// Add a sequence of hash code to the state.
/// </summary>
/// <returns>An updated <see cref="HashCode"/>.</returns>
public static HashCode operator +(HashCode hc, IEnumerable<int> others) => others.Aggregate(hc, (a, c) => a + c);
}
/// <summary>
/// <see cref="IEqualityComparer{T}"/> for <see cref="KeyValuePair{TKey, TValue}"/>.
/// </summary>
public sealed class KeyValueComparer<TKey, TValue> : IEqualityComparer<KeyValuePair<TKey, TValue>>
{
/// <summary>
/// Gets the singleton.
/// </summary>
public static KeyValueComparer<TKey, TValue> Default { get; } = new KeyValueComparer<TKey, TValue>();
private readonly IEqualityComparer<TKey> _keyComparer;
private readonly IEqualityComparer<TValue> _valueComparer;
/// <summary>
/// Initialize by specifying <see cref="IEqualityComparer{T}"/>s for key and value.
/// </summary>
public KeyValueComparer(IEqualityComparer<TKey> keyComparer = null, IEqualityComparer<TValue> valueComparer = null)
{
_keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
_valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
}
/// <summary>
/// Equality.
/// </summary>
public bool Equals(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y) => _keyComparer.Equals(x.Key, y.Key) && _valueComparer.Equals(x.Value, y.Value);
/// <summary>
/// Hash code.
/// </summary>
public int GetHashCode(KeyValuePair<TKey, TValue> obj) => new HashCode() + _keyComparer.GetHashCode(obj.Key) + _valueComparer.GetHashCode(obj.Value);
}
/// <summary>
/// <see cref="IEqualityComparer{T}"/> for a collection.
/// </summary>
public sealed class CollectionComparer<TElement> : IEqualityComparer<ICollection<TElement>>
{
/// <summary>
/// Gets an instance using <see cref="EqualityComparer{T}.Default"/> as the element comparer.
/// </summary>
public static CollectionComparer<TElement> Default { get; } = new CollectionComparer<TElement>();
private readonly IEqualityComparer<TElement> _elementComparer;
/// <summary>
/// Initialize with a specific element comparer.
/// </summary>
public CollectionComparer(IEqualityComparer<TElement> elementComparer = null)
{
_elementComparer = elementComparer ?? EqualityComparer<TElement>.Default;
}
/// <summary>
/// Determines whether the specified objects are equal.
/// </summary>
/// <returns>
/// true if the specified objects are equal; otherwise, false.
/// </returns>
public bool Equals(ICollection<TElement> x, ICollection<TElement> y)
{
if (x == null) return y == null;
if (y == null) return false;
return x.Count == y.Count && x.SequenceEqual(y, _elementComparer);
}
/// <summary>
/// Returns a hash code for the specified object.
/// </summary>
/// <returns>
/// A hash code for the specified object.
/// </returns>
/// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
public int GetHashCode(ICollection<TElement> obj)
{
var result = new HashCode() + typeof(TElement).GetHashCode();
if (obj == null) return result;
result += obj.Count;
result += obj.Select(element => _elementComparer.GetHashCode(element));
return result;
}
}
Usage:
void DoWork(Type type)
{
var props = type.GetProperties().Where(p => p.HasAttribute(MyAttribute)).ToList();
var tupleFactory = TupleFactory.Create(props.Select(p => new KeyValuePair<string, Type>(p.Name, p.PropertyType)));
var param = Expression.Parameter(type, "x");
var newEx = tupleFactory.MakeNewExpression(props.Select(p => Expression.Property(param, p)));
var lambda = Expression.Lambda(newEx, param); // <-- type is LambdaExpression, not dynamic
MyFunction(lambda);
}

Related

Cant bind RouteValueDictionary as HtmlAttributes to EditorFor

I'm trying to make a simple HtmlHelper to create a EditorFor that deal with List<T> index childs.
I did some like this
public static IHtmlString EditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper
, Expression<Func<TModel, TValue>> exp
, Expression<Func<TModel, int>> expId
, object htmlAttributes = null)
{
//Id value
var id = expId.Compile().Invoke(htmlHelper.ViewData.Model);
//Prefix
var prefix = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix;
//Propertyname
var propertyName = ExpressionHelper.GetExpressionText(exp);
//Create id and name for the EditorFor
var htmlId = $"{prefix}_{id}__{propertyName}";
var htmlName = $"{prefix}[{id}].{propertyName}";
//Create the must have attributes.
var attributes = new
RouteValueDictionary(
new {
id = htmlId,
#Name = htmlName
});
//if htmlAttributes paramter has values, will merge
if(htmlAttributes != null){
//merge..
foreach (var attr in new RouteValueDictionary(htmlAttributes).Where(attr => !attributes.ContainsKey(attr.Key)))
{
attributes.Add(attr.Key,attr.Value);
}
}
//Create a editor for
var editor = htmlHelper.EditorFor(exp, new
{
htmlAttributes = attributes
});
return new HtmlString(editor.ToString());
}
In the view i'm using it like
#Html.EditorFor(x => x.GradienteDeEntrada, x => x.Id)
My problem here, is that the Html markup generated is
<input count="2" keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" autocomplete="off" class=" decimal" data-val="true" data-val-number="El campo Gradiente de entrada debe ser un nĂºmero." id="DatosTermicos_GradienteEntrada" name="DatosTermicos.GradienteEntrada" type="text" value="">
I try converting it to HtmlHelper with this answer or dynamic with this other but when i use any of this methods, both Id and Name are just ignored.
If I create the htmlAttributes as a object
var attributes = new { id = htmlId, #Name = htmlName };
work just fine, the problem is that I don't know how to merge it with the received parameters. How can I pass the RouteValueDictionary with my HtmlAttributes to the EditorFor?
I solve it using this answer from Abdul Rauf based on converting the RouteValueDictionary in Anonymous Object (System.Object) instead of dynamic.
This is the 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;
}
The AnonymousType class code :
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;
}
}

Static method to swap the values of two objects' property values using Expressions

I'm trying to make a utility function that can Swap two property values given by two lambda expressions - assuming that both expressions indicate properties that have a getter and a setter:
Swap(() => John.Lunch, () => Jimmy.Lunch);
I imagine the method would need to look something like this, but I'm having trouble pulling it together.
private static void Swap<TProperty>(
Expression<Func<TProperty>> first,
Expression<Func<TProperty>> second)
{
PropertyInfo firstProp = (PropertyInfo)((MemberExpression)first.Body).Member;
PropertyInfo secondProp = (PropertyInfo)((MemberExpression)second.Body).Member;
object firstObj = (((first.Body as MemberExpression).Expression as MemberExpression)
.Expression as ConstantExpression).Value;
object secondObj = (((second.Body as MemberExpression).Expression as MemberExpression)
.Expression as ConstantExpression).Value;
TProperty temp = (TProperty)firstProp.GetValue(firstObj);
firstProp.SetValue(firstObj, secondProp.GetValue(secondObj));
secondProp.SetValue(secondObj, temp);
}
Getting to the "subject" object of the expression is proving to be difficult, although I'm pretty sure it's possible.
You can write the swap itself with Expression trees:
private static void Swap<TProperty>(
Expression<Func<TProperty>> first,
Expression<Func<TProperty>> second)
{
var firstMember = first.Body as MemberExpression;
var secondMember = second.Body as MemberExpression;
var variable = Expression.Variable(typeof(TProperty));
var firstMemberAccess = Expression.MakeMemberAccess(firstMember.Expression, firstMember.Member);
var secondMemberAccess = Expression.MakeMemberAccess(secondMember.Expression, secondMember.Member);
var block = Expression.Block(new []{ variable },
Expression.Assign(variable, firstMemberAccess),
Expression.Assign(firstMemberAccess, secondMemberAccess),
Expression.Assign(secondMemberAccess, variable)
);
Expression.Lambda<Action>(block).Compile()();
}
Example:
class A { public int P { get; set; } }
class B { public int P2 { get; set; } }
var a = new A { P = 5 };
var b = new B { P2 = 10 };
Swap(() => a.P, () => b.P2);
I tried to write code as self explanatory as possible so I will let the comments do the talking. The code needs error checking but I will leave it up to you. Here is the working minimum. I chose a static class for Swapper but you can choose to use as instance object then use DI container too.
public static class Swapper
{
/// <summary>
/// Key used for look-ups.
/// </summary>
private struct Key
{
private readonly Type _tt1;
private readonly Type _tt2;
private readonly MemberInfo _m11;
private readonly MemberInfo _m12;
public Key(Type t1, Type t2, MemberInfo m1, MemberInfo m2)
{
_tt1 = t1;
_tt2 = t2;
_m11 = m1;
_m12 = m2;
}
public override bool Equals(object obj)
{
switch (obj)
{
case Key key:
return _tt1 == key._tt1 && _tt2 == key._tt2 && _m11 == key._m11 && _m12 == key._m12;
default:
return false;
}
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (_tt1 != null ? _tt1.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_tt2 != null ? _tt2.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_m11 != null ? _m11.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_m12 != null ? _m12.GetHashCode() : 0);
return hashCode;
}
}
}
/// <summary>
/// This is the cache used for compiled actions. Because compiling is time consuming, I think it is better to cache.
/// </summary>
private static readonly ConcurrentDictionary<Key, object> CompiledActionsCache = new ConcurrentDictionary<Key, object>();
/// <summary>
/// Main Function which does the swapping
/// </summary>
public static void Swap<TSource, TDestination, TPropertySource>(TSource source, TDestination destination, Expression<Func<TSource, TPropertySource>> first, Expression<Func<TDestination, TPropertySource>> second)
{
//Try to get value from the cache or if it is cache miss then use Factory method to create Compiled Action
var swapper = (Action<TSource, TDestination>)CompiledActionsCache.GetOrAdd(GetKey(first, second), k => Factory(first, second));
//Do the actual swapping.
swapper(source, destination);
}
/// <summary>
/// Our factory method which does all the heavy lfiting fo creating swapping actions.
/// </summary>
private static Action<TSource, TDestination> Factory<TSource, TDestination, TPropertySource>(Expression<Func<TSource, TPropertySource>> first, Expression<Func<TDestination, TPropertySource>> second)
{
//////////////This is our aim/////////////
//// var temp = obj1.Property; /////
//// obj1.Property = obj2.Property; /////
//// obj2.Property = temp; /////
//////////////////////////////////////////
// Temp value for required for swapping
var tempValue = Expression.Variable(typeof(TPropertySource), "temp_value");
// Expression assignment
// first.body is already accesing property, just use it as it is :)
var assignToTemp = Expression.Assign(tempValue, first.Body);
// Expression assignment
// second.body is already accesing property, just use it as it is :)
var secondToFirst = Expression.Assign(first.Body, second.Body);
// Final switch here
var tempToSecond = Expression.Assign(second.Body, tempValue);
// Define an expression block which has all the above assignments as expressions
var blockExpression = Expression.Block(new[] { tempValue }, assignToTemp, secondToFirst, tempToSecond);
// An expression itself is not going to swap values unless it is compiled into a delegate
// (obj1, obj2) => blockExpression from the previous line
return Expression.Lambda<Action<TSource, TDestination>>(blockExpression, first.Parameters[0], second.Parameters[0]).Compile();
}
/// <summary>
/// Key creator method.
/// </summary>
private static Key GetKey<TSource, TDestination, TPropertySource>(Expression<Func<TSource, TPropertySource>> first, Expression<Func<TDestination, TPropertySource>> second)
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var sourcePropertyInfo = ((MemberExpression)first.Body).Member;
var destinationPorpertyInfo = ((MemberExpression)second.Body).Member;
return new Key(sourceType, destinationType, sourcePropertyInfo, destinationPorpertyInfo);
}
}
Let us see how to use Swapper in action
public class From
{
public byte FromProperty { get; set; }
}
public class To
{
public byte ToProperty { get; set; }
}
var from = new From();
from.FromProperty = 5;
var to = new To();
Swapper.Swap(from, to, f => f.FromProperty, t => t.ToProperty);

Getting Enum from a Dynamically created Enum

Can you help me with this, in C#
Given an Enum
public enum InterferenceEnum
{
None = 0,
StrongNoiseSource = 1,
MediumNoiseSource = 2,
VerySensitiveSignal = 4,
SensitiveSignal = 8,
}
and a Dynamic Enum from this
public Type GenerateEnumerations(List<string> lEnumItems, string assemblyName)
{
// Create Base Assembly Objects
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName asmName = new AssemblyName(assemblyName);
AssemblyBuilder asmBuilder = appDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
// Create Module and Enumeration Builder Objects
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(assemblyName + "_module");
EnumBuilder enumBuilder = modBuilder.DefineEnum(assemblyName, TypeAttributes.Public, typeof(int));
enumBuilder.DefineLiteral("None", 0);
int flagCnt = 1;
foreach (string fmtObj in lEnumItems)
{
enumBuilder.DefineLiteral(fmtObj, flagCnt);
flagCnt++;
}
var retEnumType = enumBuilder.CreateType();
//asmBuilder.Save(asmName.Name + ".dll");
return retEnumType;
}
using the function above
List<string> nets_List = new List<string>() { "A", "B", "C" };
netListEnum = GenerateEnumerations(nets_List, "netsenum");
Now if i have a variable with value "None", i can get the enum by
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
using the first Enum, i can get the enum of string "None"
InterferenceEnum enum = (InterferenceEnum)Enum.Parse(typeof(InterferenceEnum), "None");
How can i get the enum for the dynamic generated enum?
var enum = (netListEnum.GetType())Enum.Parse(typeof(netListEnum.GetType()), "None");
the above code is wrong because i still "casting" it with the netListEnum Type, here is the updated code
var enum = Enum.Parse(netListEnum, "None");
You already have it -- "Enum.Parse()" returns you an enum of the specified type, boxed into an object. But the boxed object is of the enum type you created; if you call "GetType()" on it it returns that same type:
List<string> nets_List = new List<string>() { "A", "B", "C" };
var netListEnumType = GenerateEnumerations(nets_List, "netsenum");
var typeName = netListEnumType.Name; // returns "netsenum"
var typeTypeName = netListEnumType.GetType().Name; // returns "RuntimeType", the actual name of the instantiated Type class.
foreach (var enumName in nets_List)
{
var enumValBoxed = Enum.Parse(netListEnumType, enumName);
Console.WriteLine(enumValBoxed.ToString()); // Writes "A", "B" and "C"
Debug.Assert(enumValBoxed.GetType() == netListEnumType); // no assert yay.
}
The only problem I see with your code is that you are doing netListEnum.GetType() but netListEnum is already of type Type -- the type you created, in fact -- so that is not necessary.
If you need to pass the enum thereby created on to some generic method in a generic object, e.g. a Dictionary<string, TEnum>, you can call it via reflection with MakeGenericMethod
my Enum maker:
public class XEnum
{
private EnumBuilder enumBuilder;
private int index;
private AssemblyBuilder _ab;
private AssemblyName _name;
public XEnum(string enumname)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
_name = new AssemblyName("MyAssembly");
_ab = currentDomain.DefineDynamicAssembly(
_name, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = _ab.DefineDynamicModule("MyModule");
enumBuilder = mb.DefineEnum(enumname, TypeAttributes.Public, typeof(int));
}
/// <summary>
/// adding one string to enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public FieldBuilder add(string s)
{
FieldBuilder f = enumBuilder.DefineLiteral(s, index);
index++;
return f;
}
/// <summary>
/// adding array to enum
/// </summary>
/// <param name="s"></param>
public void addRange(string[] s)
{
for (int i = 0; i < s.Length; i++)
{
enumBuilder.DefineLiteral(s[i], i);
}
}
/// <summary>
/// getting index 0
/// </summary>
/// <returns></returns>
public object getEnum()
{
Type finished = enumBuilder.CreateType();
_ab.Save(_name.Name + ".dll");
Object o1 = Enum.Parse(finished, "0");
return o1;
}
public Type getType()
{
Type finished = enumBuilder.CreateType();
_ab.Save(_name.Name + ".dll");
return finished;
}
/// <summary>
/// getting with index
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public object getEnum(int i)
{
Type finished = enumBuilder.CreateType();
_ab.Save(_name.Name + ".dll");
Object o1 = Enum.Parse(finished, i.ToString());
return o1;
}
}
to make Enum From String Array:
public static object STE(string[] #enum)
{
if (#enum.Length > 0)
{
XEnum xe = new XEnum("Enum");
xe.addRange(#enum);
return xe.getEnum();
}
else return null;
}
to get a selected string from enum :
public static object STE(string sel, string[] #enum)
{
XEnum xe = new XEnum("Enum");
xe.addRange(#enum);
var obj= xe.getType();
return Enum.Parse(obj, sel);
}
to use STE's put them into static class,
so to use this :
string[] ab = {"a", "b"};
object abEnum = STE(ab); //creates Enum
private object aEnum = STE("a", ab); //gets selected Value

MethodCallExpression used in AssignmentExpression returns default values

I am working on a simple ORM for my company and have used reflection for automatic property population from queries to this point. That is obviously quite slow and I would like to improve that performance with Expression Trees. I spent a good amount of time following examples and reading into the appropriate calls and my code compiles and executes now! However, I have a MethodCallExpression that performs basic DBNull checks and the likes that appears to be working properly, but when the value is assigned to the property it sends the types default value.
First up the actual code:
public static void PopulateFromReaderUsingExpression(Descriptor descriptor, IDataRecord reader)
{
if (descriptor == null)
throw new ArgumentNullException("descriptor");
if (reader == null)
throw new ArgumentNullException("reader");
string[] AvailableColumnsInReader = new string[reader.FieldCount];
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
AvailableColumnsInReader[i] = reader.GetName(i).ToUpper(CultureInfo.InvariantCulture);
}
var statements = new List<Expression>();
ParameterExpression readerExp = Expression.Parameter(typeof(IDataRecord));
ParameterExpression descriptorExp = Expression.Variable(descriptor.GetDescriptorType(), "descriptor");
BinaryExpression createInstanceExp = Expression.Assign(
descriptorExp, Expression.New(descriptor.GetDescriptorType()));
statements.Add(createInstanceExp);
foreach (KeyValuePair<PropertyInfo, PropertyMapping> pair in descriptor.ReadablePropertiesAndDataNames
.Where(property => AvailableColumnsInReader.Contains(property.Value.ReturnName.ToUpper(CultureInfo.InvariantCulture))))
{
MemberExpression propertyExp = Expression.Property(descriptorExp, pair.Key);
IndexExpression readValue =
Expression.MakeIndex(readerExp, typeof(IDataRecord).GetProperty("Item", new[] { typeof(string) }),
new[] { Expression.Constant(pair.Value.ReturnName) });
MethodCallExpression castValueExp =
Expression.Call(typeof(Descriptor)
.GetMethod("CastValue",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[]
{
typeof(Type), typeof(object), typeof(object)
},
null), Expression.Constant(pair.Key.PropertyType, typeof(Type)), readValue, Expression.Constant(null));
BinaryExpression assignmentExp = Expression.Assign(propertyExp, Expression.Convert(castValueExp, pair.Key.PropertyType));
statements.Add(assignmentExp);
}
var body = Expression.Block(new ParameterExpression[] { descriptorExp }, statements);
Expression.Lambda<Action<IDataRecord>>(body, readerExp).Compile()(reader);
}
The method that is being call by the MethodCallExpression and its overload:
/// <summary>
/// Detects if a value is DBNull, null, or has value.
/// </summary>
/// <param name="newType">The new type.</param>
/// <param name="value">The value.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="typeName">Name of the type from the database (used for date/time to string conversion).</param>
/// <returns>Value as type T if value is not DBNull, null, or invalid cast; otherwise defaultValue.</returns>
public static object CastValue(Type newType, object value, object defaultValue, string typeName)
{
object returnValue;
if (value is DBNull || value == null)
returnValue = defaultValue;
else if (newType == typeof(bool) && (value.GetType() == typeof(Int16) || value.GetType() == typeof(Int32)))
returnValue = ((object)(int.Parse(value.ToString(), CultureInfo.InvariantCulture) > 0 ? true : false));
else if (newType == typeof(int) && value.GetType() == typeof(long))
returnValue = ((object)((int)((long)value)));
else if (newType == typeof(int) && value.GetType() == typeof(decimal))
returnValue = ((object)((int)((decimal)value)));
else if (newType == typeof(string))
{
returnValue = value.ToString();
if (!string.IsNullOrEmpty(typeName))
if (typeName == "date")
returnValue = ((DateTime)value).ToString("MM/dd/yyyy", CultureInfo.CurrentCulture);
}
else
returnValue = value;
return returnValue;
}
/// <summary>
/// Casts the value.
/// </summary>
/// <param name="newType">The new type.</param>
/// <param name="value">The value.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>System.Object.</returns>
public static object CastValue(Type newType, object value, object defaultValue)
{
return CastValue(newType, value, defaultValue, null);
}
I have confirmed that values are making into the method and returned, but are the lost along the way, my guess is in the assignment operation.
Here I will include relevant method signatures used in the code example:
public virtual Dictionary<PropertyInfo, PropertyMapping> ReadablePropertiesAndDataNames
/// <summary>
/// THe object Orochi CRUDE uses to map properties to database actions.
/// </summary>
public class PropertyMapping
{
/// <summary>
/// Initializes a new instance of the <see cref="PropertyMapping" /> class.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="parameterName">Name of the parameter.</param>
/// <param name="returnName">Name of the return.</param>
/// <exception cref="System.ArgumentNullException">property</exception>
public PropertyMapping(PropertyInfo property, string returnName)
{
if (property == null)
throw new ArgumentNullException("property");
Contract.EndContractBlock();
this.ReturnName = !string.IsNullOrWhiteSpace(returnName) ? returnName : property.Name;
}
/// <summary>
/// Gets the name of the return.
/// </summary>
/// <value>
/// The name of the return.
/// </value>
public string ReturnName { get; private set; }
}
Here is the DebugInfo from my statement block:
.Block(Models.Billing.Claims.BillingQueue $descriptor) {
$descriptor = .New Models.Billing.Claims.BillingQueue();
$descriptor.ClaimWorkQueueId = (System.Int32).Call Orochi.CrudeData.Descriptor.CastValue(
.Constant<System.Type>(System.Int32),
$var1.Item["ClaimWorkQueueId"],
null);
$descriptor.WorkQueueName = (System.String).Call Orochi.CrudeData.Descriptor.CastValue(
.Constant<System.Type>(System.String),
$var1.Item["WorkQueueName"],
null);
$descriptor.Count = (System.Int32).Call Orochi.CrudeData.Descriptor.CastValue(
.Constant<System.Type>(System.Int32),
$var1.Item["ClaimCount"],
null)
}
I missed that I was creating a new instance of an object and setting values to it instead of by reference. I added the return statement and modified the code to use a return value.
/// <summary>
/// Builds the mapping expression.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <param name="reader">The reader.</param>
/// <returns>LambdaExpression.</returns>
public static Expression<Func<IDataRecord, object>> BuildMappingExpression(IDescriptor descriptor, IDataRecord reader, string[] availableColumns)
{
var statements = new List<Expression>();
ParameterExpression readerExp = Expression.Parameter(typeof(IDataRecord));
ParameterExpression descriptorExp = Expression.Variable(descriptor.GetDescriptorType(), "descriptor");
BinaryExpression createInstanceExp = Expression.Assign(
descriptorExp, Expression.New(descriptor.GetDescriptorType()));
statements.Add(createInstanceExp);
foreach (KeyValuePair<PropertyInfo, PropertyMapping> pair in descriptor.ReadablePropertiesAndDataNames
.Where(property => availableColumns.Contains(property.Value.ReturnName.ToUpper(CultureInfo.InvariantCulture))))
{
MemberExpression propertyExp = Expression.Property(descriptorExp, pair.Key);
IndexExpression readValue =
Expression.MakeIndex(readerExp, typeof(IDataRecord).GetProperty("Item", new[] { typeof(string) }),
new[] { Expression.Constant(pair.Value.ReturnName) });
MethodCallExpression castValueExp =
Expression.Call(typeof(Descriptor)
.GetMethod("CastValue",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[]
{
typeof(Type), typeof(object), typeof(object)
},
null), Expression.Constant(pair.Key.PropertyType, typeof(Type)), readValue, Expression.Constant(null));
BinaryExpression assignmentExp = Expression.Assign(propertyExp, Expression.Convert(castValueExp, pair.Key.PropertyType));
statements.Add(assignmentExp);
}
statements.Add(descriptorExp);
var body = Expression.Block(new ParameterExpression[] { descriptorExp }, statements);
return Expression.Lambda<Func<IDataRecord, object>>(body, readerExp);
}

DuplexChannelFactory < Reflection Interface >

Using TypeGenerator Class
public class TypeGenerator
{
/// <summary>
/// internal cache for already generated types
/// </summary>
private static Dictionary<Type, Type> asyncTypeCache = new Dictionary<Type, Type>();
/// <summary>
/// provides a cache for the modules
/// </summary>
private static Dictionary<string, ModuleBuilder> moduleBuilderCache = new Dictionary<string, ModuleBuilder>();
/// <summary>
/// Generates the Async version of the TSync type.
/// the generate type repects the AsyncPattern and it is already decorated with attributes for WCF operations
/// </summary>
/// <typeparam name="TSync">The Sync version of type</typeparam>
/// <returns>A type that is the Async version of the TSync type, that implements the AsyncPattern for WCF</returns>
public Type GenerateAsyncInterfaceFor<TSync>() where TSync : class
{
Type syncType = typeof(TSync);
if (asyncTypeCache.ContainsKey(syncType)) return asyncTypeCache[syncType];
if (!syncType.IsInterface) throw new InvalidOperationException("Only interface type could be transformed");
var asynchAssemblyName = string.Format("{0}.Async", syncType.Namespace);
TypeBuilder typeBuilder =
GetModuleBuilder(asynchAssemblyName)
.DefineType(
string.Format("{0}.Async.{1}", syncType.Namespace, syncType.Name),
(syncType.IsPublic ? TypeAttributes.Public : 0) |
TypeAttributes.Abstract |
TypeAttributes.Interface);
foreach (var method in syncType.GetAllInterfaceMethods())
{
AddBeginAsynchVersionForMethod(typeBuilder, method, #"http://tempuri.org");
AddEndAsynchVersionForMethod(typeBuilder, method);
}
var serviceContractConstructor = typeof(ServiceContractAttribute).GetConstructor(new Type[0]);
var attribuiteBuilder =
new CustomAttributeBuilder(
serviceContractConstructor,
new object[0]);
typeBuilder.SetCustomAttribute(attribuiteBuilder);
Type asyncType = typeBuilder.CreateType();
asyncTypeCache.Add(syncType, asyncType);
return asyncType;
}
/// <summary>
/// Creates a End verison of a sync method, that implements the AsyncPattern
/// </summary>
/// <param name="typeBuilder">the tipebuilder where the type is being building</param>
/// <param name="method">information about the sync version of the method</param>
private void AddEndAsynchVersionForMethod(TypeBuilder typeBuilder, MethodInfo method)
{
string endMethodName = string.Format("End{0}", method.Name);
var parameters =
method.GetParameters()
.Select(x =>
new
{
Type = x.ParameterType,
Name = x.Name,
Attributes = x.Attributes,
})
.ToList();
parameters.Add(
new
{
Type = typeof(IAsyncResult),
Name = "asyncResult",
Attributes = ParameterAttributes.None,
});
var methodBuilder =
typeBuilder
.DefineMethod(
endMethodName,
method.Attributes,
method.CallingConvention,
method.ReturnType,
parameters.Select(x => x.Type).ToArray());
for (int i = 0; i < parameters.Count(); i++)
{
var parameter = parameters[i];
methodBuilder.DefineParameter(i + 1, parameter.Attributes, parameter.Name);
}
}
/// <summary>
/// Creates a Begin verison of a sync method, that implements the AsyncPattern
/// </summary>
/// <param name="typeBuilder">the tipebuilder where the type is being building</param>
/// <param name="method">information about the sync version of the method</param>
private void AddBeginAsynchVersionForMethod(TypeBuilder typeBuilder, MethodInfo method, string nameSpace)
{
string beginMethodName = string.Format("Begin{0}", method.Name);
var parametersTypeList = method.GetParameters().Select(x => x.ParameterType).ToList();
var parametersNameList = method.GetParameters().Select(x => x.Name).ToList();
var parametersAttributeList = method.GetParameters().Select(x => x.Attributes).ToList();
parametersTypeList.Add(typeof(AsyncCallback));
parametersAttributeList.Add(ParameterAttributes.None);
parametersNameList.Add("callBack");
parametersTypeList.Add(typeof(object));
parametersAttributeList.Add(ParameterAttributes.None);
parametersNameList.Add("statusObject");
var methodBuilder =
typeBuilder
.DefineMethod(
beginMethodName,
method.Attributes,
method.CallingConvention,
typeof(IAsyncResult),
parametersTypeList.ToArray());
for (int i = 0; i < parametersTypeList.Count(); i++)
{
methodBuilder.DefineParameter(i + 1, parametersAttributeList[i], parametersNameList[i]);
}
var operationContractConstructor = typeof(OperationContractAttribute).GetConstructor(new Type[0]);
var asynchPatternProperty = typeof(OperationContractAttribute).GetProperty("AsyncPattern");
var actionProperty = typeof(OperationContractAttribute).GetProperty("Action");
var actionValue = string.Format("{0}/{1}/{2}", nameSpace, method.DeclaringType.Name, method.Name);
var replyActionProperty = typeof(OperationContractAttribute).GetProperty("ReplyAction");
var replyActionValue = string.Format("{0}/{1}/{2}Response", nameSpace, method.DeclaringType.Name, method.Name);
var attribuiteBuilder =
new CustomAttributeBuilder(
operationContractConstructor,
new object[0],
new[] { asynchPatternProperty, actionProperty, replyActionProperty },
new object[] { true, actionValue, replyActionValue });
methodBuilder.SetCustomAttribute(attribuiteBuilder);
}
/// <summary>
/// provides a ModelBuilder with the required assembly name
/// </summary>
/// <param name="requiredAssemblyName">the assembly name for where the type will be generated in</param>
/// <returns>a model builder</returns>
/// <remarks>in this version the model builder is not cached, it could be interesting to generate all the types in the same assembly by caching the model builder</remarks>
private ModuleBuilder GetModuleBuilder(string requiredAssemblyName)
{
if (moduleBuilderCache.ContainsKey(requiredAssemblyName))
{
return moduleBuilderCache[requiredAssemblyName];
}
AssemblyName assemblyName = new AssemblyName(requiredAssemblyName);
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
moduleBuilderCache[requiredAssemblyName] = moduleBuilder;
return moduleBuilder;
}
}
and TypeExtentions Class
public static class TypeExtensions
{
/// <summary>
/// extracts all the methods fromthe given interface type and from all the inherited ones too
/// </summary>
/// <param name="type">the type fromwhich extracts all the methods</param>
/// <returns>list of MemberInfo representing the methods</returns>
public static IEnumerable<MethodInfo> GetAllInterfaceMethods(this Type type)
{
IEnumerable<MethodInfo> methods = type.GetMethods();
foreach (var subType in type.GetInterfaces())
{
methods = methods.Union(GetAllInterfaceMethods(subType));
}
return methods;
}
}
I 'm able to convert a Synchronous Interface to Asynchronous one.
How to use DuplexChannelFactory with a pre-defined reflection Asynchronous interface ?
var myInterface = new TypeGenerator ( ) . GenerateAsyncInterfaceFor<mySynchronousInterface> ( );
var Client = new DuplexChannelFactory<myInterface> ( new InstanceContext ( new myClass ( ) ) , "myConfiguration" );
I'm getting the following issue:
The type or namespace name 'myInterface' could not be found (are you
missing a using directive or an assembly reference?)
I'm trying to code a mid-tier WCF interface.
The syntax you are using is for compile time typing, of course the types you are making are generated at runtime, so it isn't going to work. It is possible though.
How to: Examine and Instantiate Generic Types with Reflection
Here's how the code will look (I'm assuming myClass was already defined with source code, if not it would just be another Activator.CreateInstance call)
Type t = typeof(DuplexChannelFactory<>);
Type typedDuplexChannelFactory = t.MakeGenericType(new Type[]{myInterface});
var Client = Activator.CreateInstance(typedDuplexChannelFactory, new object[]{new InstanceContext ( new myClass ( ) ) , "myConfiguration"});

Categories