1

Say I have the following C# code:

//build an object
var mynewObj = new Thing();

//build an assignment value
var val = "abc";

var memberExpression = "x.PropertyX.Id = y";

[? some stuff happens ?]

Assert.IsTrue(myNewObj.PropertyX.Id == "abc");

memberExpression is a value in some database. I want to take these pieces, build an expression, and compile/execute it. I need to do this ~30 times per second for hours, so it must be fast and light on the memory.

4

3 回答 3

3

Your best bet would be to use Expressions to build an Action, compile it and cache it. Below is a slightly simplified example illustrating how to do this. In this case I'm only doing one level deep in the property graph.

    /// <summary>
    /// Build a lambda expression for a setter
    /// </summary>
    public static Action<T, U> GetSetter<T, U>(string propertyName)
    {
        // TODO: Maintain a dictionary mapping typeof(T)+property onto the 
        // resulting Action so this can be cached

        PropertyInfo property = typeof(T).GetProperty(propertyName);
        var setMethod = property.GetSetMethod();

        var parameterT = Expression.Parameter(typeof(T), "x");
        var parameterU = Expression.Parameter(typeof(U), "y");

        var newExpression =
            Expression.Lambda<Action<T, U>>(
                Expression.Call(parameterT, setMethod, parameterU),
                parameterT,
                parameterU
            );

        return newExpression.Compile();
    }

To use it:-

        //build an object
        var mynewObj = new Thing();

        //build an assignment value
        var val = "abc";

        var propertyName = "PropertyX";
        var setter = GetSetter<Thing, string>(propertyName);

        // Execute the cached setter (it's really fast!)
        setter(mynewObj, val);

        Debug.Assert(mynewObj.PropertyX == "abc") ;
于 2013-09-18T03:59:40.170 回答
2

You're going to have trouble doing this 30 times per second for hours. Every compile will create a different in-memory assembly, and there's no way to unload a loaded assembly without tearing down the app domain. So your memory footprint will grow without bound.

If you want to prevent unbounded memory use, you have to compile and load the assembly in a separate app domain. You can then tear down that app domain to unload the loaded assembly.

But creating a new app domain, compiling an assembly, and tearing down an app domain 30 times per second? Possible, I suppose. Perhaps you could create an app domain and load assemblies into it for a minute, then tear down that app domain and create a new one. That would at least limit your memory usage somewhat, and also cut down on the processing. But I don't know what kind of footprint 1,800 loaded assemblies would have.

You definitely need to experiment with the System.CodeDom namespace. I suspect, though, that you're asking a bit too much. The comment recommending an interpreted language might be the way to go. It's really hard to say without more information about your application.

于 2013-09-18T00:27:05.670 回答
1

Not a complete answer but can be used as a starting point, if you don´t find something better or more complete.

Try to make it simple, and light using some code like this:

public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

Get property value from string using reflection in C#

于 2013-09-18T00:31:31.750 回答