开发者

Exception when building Expression to call StringBuilder.Append(Object) with DateTime

I've built a ToStringBuilder (found here) which reflects on types and dynamically builds Expressions to compile fast ToString methods.

It works well but I've just discovered it errors on DateTimes. It chokes when trying to build an call to StringBuilder.Append(Object) passing a DateTime. Do I need to create an expression to box value types? How is this best done?

I've created the following test case to demonstrate the failure.

    // passes
    [Test]
    public void AppendDateTime()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(new DateTime());
    }


    // throws 
    [Test]
    public void ExpressionAppendDateTime()
    {
        ParameterExpression sbArgExpression = Expression.Parameter(typeof(StringBuilder), "sb");
        ParameterExpression dateTimeArgExpression = Expression.Parameter(typeof(DateTime), "dateTime");

        var appendMethod = typeof(StringBuilder).GetMethod("Append", new[] {typeof(DateTime)});
        var call = Expression.Call(sbArgExpression, appendMethod, dateTimeArgExpression);

        // throws on this line
        var lambda = Expression.Lambda<Action<StringBuilder, DateTime>>(call, sbArgExpression, dateTimeArgExpression).Compile();  

        var datetime = new DateTime();
        var sb = new StringBuilder();
        lambda.Invoke(sb, datetime);
    }
开发者_运维问答

The exception is..

System.ArgumentException was unhandled by user code
  Message=Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'System.Text.StringBuilder Append(System.Object)'
  Source=System.Core
  StackTrace:
       at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
       at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
       at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
       at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
       at Tests.TestToStringBuilder.ExpressionAppendDateTime() in 
  InnerException: 


Solved it, had to use Expression.TypeAs to type non-primitive value types as Object

    [Test]
    public void ExpressionAppendDateTime()
    {
        ParameterExpression sbArgExpression = Expression.Parameter(typeof(StringBuilder), "sb");
        ParameterExpression dateTimeArgExpression = Expression.Parameter(typeof(DateTime), "dateTime");

        var appendMethod = typeof(StringBuilder).GetMethod("Append", new[] {typeof(DateTime)});

        Type t = typeof(DateTime);
        Expression arg;
        if (t.IsValueType && !t.IsPrimitive)
        {
            arg = Expression.TypeAs(dateTimeArgExpression, typeof(object));
        }
        else
        {
            arg = dateTimeArgExpression;
        }

        var call = Expression.Call(sbArgExpression, appendMethod, arg);

        var lambda = Expression.Lambda<Action<StringBuilder, DateTime>>(call, sbArgExpression, dateTimeArgExpression).Compile();

        var datetime = new DateTime();
        var sb = new StringBuilder();
        lambda.Invoke(sb, datetime);
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜