Search code examples
c#dynamicreflectionexpression-treesanonymous-types

How to build an anonymous object with expression trees


I have a class

public class SomeClass
{
    public int num { get; set; }
    public string str{ get; set; }
}

I need to construct a lambda expression like: (x => new {new_num= x.num, new_str= x.str})

Properties are listed in some enumerable object (that's important). Let's say List<KeyValuePair<string, string>>

My code is:

// Test properties list
var listOfParams = new List<KeyValuePair<string, string>>();
listOfParams.Add(new KeyValuePair<string, string>("new_num","num"));
listOfParams.Add(new KeyValuePair<string, string>("new_str","str"));

// SomeClass as particular test case
var tModelType = typeof(SomeClass); 

ParameterExpression pe = Expression.Parameter(tModelType, "m");
NewExpression ne = Expression.New(typeof(object)); //<-- trying to emulate `new object{}`

List<Expression> lInit = new List<Expression>(); 

PropertyInfo pi;
string sAnonymousProperty;

Type propertyType;
foreach(var paramElem in listOfParams)
{
   pi = tModelType.GetProperty(paramElem.Value);
   propertyType = pi.PropertyType;
   sAnonymousProperty = paramElem.Value;

   Expression bind = ??Expression??  // <-- here I need to build binding expression

   lInit.Add( bind );
}

ListInitExpression lie = Expression.ListInit(ne, lInit);

LambdaExpression leResult = Expression.Lambda(lie, pe);

I can't figure out binding expression, because it needs MemberInfo, which anonymous object hasn't got. Also I can't walkaround it using new { new_num = 0, new_str = "" }.GetType() since properties are unknown and come as some array as a parameter.

Maybe my approach is invalid at all and someone will suggest another way, but main idea is to obtain lambda-expression/"Func"-delegate that creates anonymous object with dynamic remapped properties.

Any help is appreciated.


Solution

  • The approach is basically invalid, because there's no appropriate type to refer to. An anonymous type is just a normal type as far as the CLR is concerned - the compiler just generates the type for you. (In the Microsoft implementation it actually generates a generic type, which is used for every anonymous type with the same property names used in the same order.)

    So in order to emulate this, you'd need to create your own type as well. Alternatively, you could use Tuple<T1, T2> etc - using the right tuple type based on the number of properties you have.