C# Dynamic Type Initializer
I'm trying to build something like the C# type initalizer dynamically:
MyClass class = new MyClass { MyStringProperty= inputString };
I want to build a generic method that reflects over a given type once and returns a delegate which creates a new instance of the class and populates it based on the input parameter. The method signature might look like this:
Func<string,T> CreateFunc<T>();
And calling the resulting function would create a new instance of 'T' with (for example) every public property with of type String to the value of the input string argument.
So assuming that 'MyClas开发者_JAVA技巧s' has only MyStringProperty, the code below would be functionally equivalent to the code at the beginning:
var func = CreateFunc<MyClass>();
func.Invoke(inputString);
I'm pretty familiar with the System.Reflection and System.Linq.Expressions namespaces, and I've done some moderately complex things like this in the past, but this one has me stumped. I want to build a compiled delegate, not simply iterate through the properties using reflection.
Thanks!
In CLR 4.0 you'll be able to build complete statements with Expressions.
Until then, you're looking at a code-gen job. The quickest way to prototype it would be by building C# in a StringBuilder and then calling the compiler on it. With caching it would perform okay.
The hardcore way to do it would be to generate the IL and use Reflection Emit to build the method, thus avoiding calling out to the compiler.
Uh, yeah so I was just making things way too complicated for myself. This is the method I was looking for:
public static Func<string, T> CreateFunc<T>()
where T : class
{
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
var param = Expression.Parameter(typeof(string),"o");
var constructorInfo = typeof(T).GetConstructor(new Type[] { });
List<MemberBinding> bindings = new List<MemberBinding>();
foreach (var property in properties)
bindings.Add(Expression.Bind(property, param));
var memberInit = Expression.MemberInit(Expression.New(constructorInfo), bindings);
var func = Expression.Lambda<Func<string, T>>(memberInit, new ParameterExpression[] {param}).Compile();
return func;
}
Unfortunately, I don't see this happening, although I'm no expert when it comes to the deep vodoo you can do with expressions and delegates.
The way I see it, you can only do this with reflection. Without reflection, you need to know at compile time what the names of each property you want to set are. You could do individual functions for each separate class you wanted to support, but that seems counter to the requirement of a generic, one-size-fits-all function.
May I ask why the function in the first place? Some form of dependency injection?
精彩评论