views:

242

answers:

3

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 'MyClass' 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!

+1  A: 

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.

Daniel Earwicker
A: 

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?

Randolpho
No, this is certainly possible. Reflection emit (or calling the compiler on a string of runtime-generated C# source) allow you to effectively continue the compilation process in little delayed bursts, at runtime. You use reflection to get the information, and build code from it, and cache the resulting delegate so that you don't have to perform the reflection ever again.
Daniel Earwicker
The reason for it is because I have to deploy an assembly I won't be able to change in the future but I don't want to create a hard dependancy on the current type. I'm pretty sure I just figured it out, I'll post whatever I come up with.
Paul
+1  A: 

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;            
}
Paul
Looks like you're still using reflection, you're just (essentially) caching the result of the reflection.
Randolpho
Ah cool, I forgot there were Expression node types concerned with property initialization, and assumed that would need several separate statements. @Randolpho, yes, that's what I tried to explain in my comment to your answer.
Daniel Earwicker
Yes exactly, I didn't realize the initializer existed and just assumed I'd have to forge my own. This was way simpler than I expected when I wrote the question.
Paul