How to create LINQ Expression Tree to select an anonymous type
This can be done, as mentioned, with the help of Reflection Emit and a helper class I've included below. The code below is a work in progress, so take it for what it's worth... 'it works on my box'. The SelectDynamic method class should be tossed in a static extension method class.
As expected, you won't get any Intellisense since the type isn't created until runtime. Works good on late-bound data controls.
public static IQueryable SelectDynamic(this IQueryable source, IEnumerable<string> fieldNames)
{
Dictionary<string, PropertyInfo> sourceProperties = fieldNames.ToDictionary(name => name, name => source.ElementType.GetProperty(name));
Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.Values);
ParameterExpression sourceItem = Expression.Parameter(source.ElementType, "t");
IEnumerable<MemberBinding> bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, Expression.Property(sourceItem, sourceProperties[p.Name]))).OfType<MemberBinding>();
Expression selector = Expression.Lambda(Expression.MemberInit(
Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem);
return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Select", new Type[] { source.ElementType, dynamicType },
Expression.Constant(source), selector));
}
public static class LinqRuntimeTypeBuilder
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static AssemblyName assemblyName = new AssemblyName() { Name = "DynamicLinqTypes" };
private static ModuleBuilder moduleBuilder = null;
private static Dictionary<string, Type> builtTypes = new Dictionary<string, Type>();
static LinqRuntimeTypeBuilder()
{
moduleBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run).DefineDynamicModule(assemblyName.Name);
}
private static string GetTypeKey(Dictionary<string, Type> fields)
{
//TODO: optimize the type caching -- if fields are simply reordered, that doesn't mean that they're actually different types, so this needs to be smarter
string key = string.Empty;
foreach (var field in fields)
key += field.Key + ";" + field.Value.Name + ";";
return key;
}
public static Type GetDynamicType(Dictionary<string, Type> fields)
{
if (null == fields)
throw new ArgumentNullException("fields");
if (0 == fields.Count)
throw new ArgumentOutOfRangeException("fields", "fields must have at least 1 field definition");
try
{
Monitor.Enter(builtTypes);
string className = GetTypeKey(fields);
if (builtTypes.ContainsKey(className))
return builtTypes[className];
TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);
foreach (var field in fields)
typeBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public);
builtTypes[className] = typeBuilder.CreateType();
return builtTypes[className];
}
catch (Exception ex)
{
log.Error(ex);
}
finally
{
Monitor.Exit(builtTypes);
}
return null;
}
private static string GetTypeKey(IEnumerable<PropertyInfo> fields)
{
return GetTypeKey(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
public static Type GetDynamicType(IEnumerable<PropertyInfo> fields)
{
return GetDynamicType(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
}
Expression tree to initialize new anonymous object with arbitrary number of properties
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);
}
C# LINQ build expression with anonymous type
I'm assuming that the "Name" and "Test_Result" here are flexible and cannot be hard-coded.
Anonymous types are fully defined regular classes; the only interesting thing about them is that the compiler provides the details instead of you.
I would suggest that the way to handle this scenario would be to use Tuple.Create
to create an IEnumerable<Tuple<string,string>>
and refer to them as Item1
, Item2
(the names from Tuple<,>
. The other option would be to use something like ExpandoObject
, and then use either the IDictionary<string,object>
API, or the dynamic
API, to get the values back out.
For example:
string item1 = "Name";
string item2 = "Test_Result";
Type studentType = typeof(Student);
var itemParam = Expression.Parameter(studentType, "x");
var member1 = Expression.PropertyOrField(itemParam, item1);
var member2 = Expression.PropertyOrField(itemParam, item2);
var selector = Expression.Call(typeof(Tuple), "Create",
new[] { member1.Type, member2.Type }, member1, member2);
var lambda = Expression.Lambda<Func<Student, Tuple<string,string>>>(
selector, itemParam);
var currentItemFields = students.Select(lambda.Compile());
Here's the same projecting into a custom type with members name
and result
:
class ProjectedData
{
public string name { get; set; }
public string result { get; set; }
}
...
string item1 = "Name";
string item2 = "Test_Result";
Type studentType = typeof(Student);
var itemParam = Expression.Parameter(studentType, "x");
var member1 = Expression.PropertyOrField(itemParam, item1);
var member2 = Expression.PropertyOrField(itemParam, item2);
var selector = Expression.MemberInit(Expression.New(typeof(ProjectedData)),
Expression.Bind(typeof(ProjectedData).GetMember("name").Single(), member1),
Expression.Bind(typeof(ProjectedData).GetMember("result").Single(), member2)
);
var lambda = Expression.Lambda<Func<Student, ProjectedData>>(
selector, itemParam);
var currentItemFields = students.Select(lambda.Compile());
Or for the approach using a dictionary:
string[] fields = {"Name", "Test_Result"};
Type studentType = typeof(Student);
var itemParam = Expression.Parameter(studentType, "x");
var addMethod = typeof(Dictionary<string, object>).GetMethod(
"Add", new[] { typeof(string), typeof(object) });
var selector = Expression.ListInit(
Expression.New(typeof(Dictionary<string,object>)),
fields.Select(field => Expression.ElementInit(addMethod,
Expression.Constant(field),
Expression.Convert(
Expression.PropertyOrField(itemParam, field),
typeof(object)
)
)));
var lambda = Expression.Lambda<Func<Student, Dictionary<string,object>>>(
selector, itemParam);
var currentItemFields = students.Select(lambda.Compile());
How to use Expression to build an Anonymous Type?
You're close, but you have to be aware that anonymous types don't have default constructors. The following code prints { Name = def, Num = 456 }
:
Type anonType = new { Name = "abc", Num = 123 }.GetType();
var exp = Expression.New(
anonType.GetConstructor(new[] { typeof(string), typeof(int) }),
Expression.Constant("def"),
Expression.Constant(456));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
Console.WriteLine(myObj);
If you don't have to create many instances of this type, Activator.CreateInstance
will do just as well (it's faster for a few instances, but slower for many). This code prints { Name = ghi, Num = 789 }
:
Type anonType = new { Name = "abc", Num = 123 }.GetType();
object myObj = Activator.CreateInstance(anonType, "ghi", 789);
Console.WriteLine(myObj);
How to create C# LambdaExpression that returns anonymous type for SelectMany resultSelector
The way that I ended up resolving this required a paradigm shift.
Related Topics
Compression/Decompression String With C#
Why Doesn't C# Infer My Generic Types
How to Get Children of a Wpf Container by Type
Use Linq to Get Items in One List≪≫, That Are Not in Another List≪≫
Calculate the Number of Business Days Between Two Dates
What Is the Best Choice For .Net Inter-Process Communication
How to Create and Use Resources in .Net
Using C#, How Does One Figure Out What Process Locked a File
Calling Stored Procedure With Return Value
C# Getting the Path of %Appdata%
How to Get the List of Open File Handles by Process in C#
How to Use C# 7 With Visual Studio 2015
Easier Way to Debug a Windows Service
How to Get Httpcontext.Current in ASP.NET Core
Could Not Establish Trust Relationship For Ssl/Tls Secure Channel - Soap