1

我正在尝试string.Format使用 Tree 调用

我做了一些工作,因为我的供应与接受params Expression[] _ParameterExpressions的签名不匹配,它似乎不会应用隐式转换。string.Formatobject[]

我目前的解决方案是将我提供的参数转换为object[]使用

NewArrayExpression _NewArray = Expression.NewArrayInit(typeof(object), _ParameterExpressions.Select(ep => Expression.Convert(ep, typeof(object))));

并设置我的代理函数以将参数传递给string.Format(我需要这个,否则它会说它找不到匹配的签名)

static string ReplaceParameters(string format, params object[] obj)
{
    return string.Format(format, obj);
}

static IEnumerable<Expression> ReplaceStringExpression(Expression exp)
{
    yield return exp;
    yield return _NewArray;
}

最后是我的电话

ConstantExpression ce = Expression.Constant(orginalString, typeof(string));
MethodCallExpression me = Expression.Call(typeof(RuleParser), "ReplaceParameters", null,
                ReplaceStringExpression(ce).ToArray());

该表达式有效,但我不太喜欢创建包含额外装箱过程的新数组的想法。我认为在这种简单的函数调用上做得过火了。

我怎样才能改善这个string.Format电话?

==========

编辑

在我的学习上取得一些进展。我现在可以ReplaceParameters放弃但仍然不喜欢创建对象数组_NewArray

MethodCallExpression me = Expression.Call(
     typeof(string).GetMethod("Format", new Type[2] { typeof(string), typeof(object[]) }),
     ReplaceStringExpression(ce).ToArray());
4

1 回答 1

2
  1. 当 ExpressionTree 由编译器创建时 - 它将包含所有隐式所需的转换以使选定的方法重载工作

    Expression<Func<string>> compilerFactoredExpressionTree = () => string.Format("{0} and {1} and {2} and {3}", 1, "text", true, 2);
    // test
    // "1 and text and True and 2"
    string s = compilerFactoredExpressionTree.Compile()();
    // ArrayInit(Convert(1), Convert("text", Convert(2)))
    Expression methodArgs = ((MethodCallExpression)compilerFactoredExpressionTree.Body).Arguments[1];
    
  2. 如果您手动构建 ExpressionTree - 您需要自己充当编译器 - 手动插入转换或最初声明具有所需类型的值

    var parameters = new Expression[]
    {
        Expression.Constant(1, typeof(object)),
        Expression.Constant("text", typeof(object)),
        Expression.Constant(true, typeof(object)),
        Expression.Constant(2, typeof(object)),
    };
    
    var mi = new Func<string, object[], string>(string.Format).Method;
    
    var callStringFormat = Expression.Call(mi, Expression.Constant("{0} and {1} and {2} and {3}"), Expression.NewArrayInit(typeof(object), parameters));
    
    // "1 and text and True and 2"
    var lambda = Expression.Lambda<Func<string>>(callStringFormat);
    var r = lambda.Compile()();
    
于 2012-09-02T12:22:10.047 回答