C# 思维弯曲器:在运行时将字符串编译为赋值表达式

本文关键字:字符串 编译 表达式 赋值 运行时 弯曲 | 更新日期: 2023-09-27 18:31:36

>假设我有以下 C# 代码:

//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 是某个数据库中的值。我想获取这些部分,构建一个表达式,然后编译/执行它。我需要每秒执行此操作~30次,持续数小时,因此它必须快速且轻便的内存。

C# 思维弯曲器:在运行时将字符串编译为赋值表达式

最好的办法是使用表达式来构建一个动作,编译它并缓存它。 下面是一个稍微简化的示例,说明了如何执行此操作。 在这种情况下,我只在属性图的深处做一个级别。

    /// <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();
    }

使用它:-

        //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") ;

您将无法在数小时内每秒执行此操作 30 次。每次编译都会创建一个不同的内存中程序集,并且无法在不拆除应用程序域的情况下卸载加载的程序集。因此,您的内存占用量将无限增长。

如果要防止无限使用内存,则必须在单独的应用程序域中编译和加载程序集。然后,可以拆除该应用程序域以卸载加载的程序集。

但是,创建新的应用程序域、编译程序集以及每秒 30 次拆除应用程序域?我想有可能。也许您可以创建一个应用程序域并将程序集加载到其中一分钟,然后拆除该应用程序域并创建一个新应用程序域。这至少会在一定程度上限制您的内存使用,并减少处理。但我不知道 1,800 个加载的组件会有什么样的足迹。

您绝对需要试验System.CodeDom命名空间。不过,我怀疑你的要求有点太多了。推荐解释性语言的评论可能是要走的路。如果没有有关您的应用程序的更多信息,真的很难说。

不是一个完整的答案,但可以作为一个起点,如果你没有找到更好或更完整的东西。

尝试使它变得简单,并使用如下代码进行轻量级:

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

在 C# 中使用反射从字符串中获取属性值