using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; using System.Reflection; namespace Roger.Alsing { public static class TemplatedFactory { public static T Create(Expression> exp) { LambdaExpression lambda = exp as LambdaExpression; NewExpression body = null; List bindings = new List(); if (lambda.Body is MemberInitExpression) { //the expression contains property/field initializers MemberInitExpression tmpBody = lambda.Body as MemberInitExpression; body = tmpBody.NewExpression; bindings.AddRange(tmpBody.Bindings); } else { //no initializers body = lambda.Body as NewExpression; } List argsList = new List(); foreach (var arg in body.Arguments) { //create a lambda to wrap up the expression for "arg" object argValue = EvaluateExpression(arg); //add the raw value to the arg list argsList.Add(argValue); } object[] argsArr = argsList.ToArray(); //this is where you might want to modify. //eg, make it create some proxy type instead //this is an naive example so I will just create an instance //of the original type and return it.. T instance = (T)Activator.CreateInstance(typeof(T), argsArr); //apply property initializers here.. foreach (MemberBinding binding in bindings) { if (binding.Member is PropertyInfo) { //this is a property initializer MemberAssignment memberAssignment = (MemberAssignment)binding; PropertyInfo property = (PropertyInfo)binding.Member; object propertyValue = EvaluateExpression(memberAssignment.Expression); property.SetValue(instance, propertyValue, null); } else if (binding.Member is FieldInfo) { //this is a field initializer MemberAssignment memberAssignment = (MemberAssignment)binding; FieldInfo field = (FieldInfo)binding.Member; object fieldValue = EvaluateExpression(memberAssignment.Expression); field.SetValue(instance, fieldValue); } } return instance; } private static object EvaluateExpression(Expression arg) { LambdaExpression argLambda = Expression.Lambda(arg); //compile the lambda var argDel = argLambda.Compile(); //get the arg value by invoking the compiled lambda object argValue = argDel.DynamicInvoke(); return argValue; } } }