Исключение при построении Expression для вызова StringBuilder.Append (Object) с DateTime - PullRequest
1 голос
/ 28 марта 2011

Я построил ToStringBuilder (найдено здесь ), который отражает типы и динамически создает Expression s для быстрой компиляции ToString методов.

Он работает хорошо, но яМы только что обнаружили ошибки на DateTimes.Он задыхается при попытке построить вызов на StringBuilder.Append(Object), пропуская DateTime.Нужно ли создавать выражения для типов значений бокса?Как это лучше всего сделать?

Я создал следующий тестовый пример, чтобы продемонстрировать ошибку.

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

Исключение составляет ..

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: 

1 Ответ

4 голосов
/ 28 марта 2011

Решено, пришлось использовать Expression.TypeAs для ввода типов не примитивных значений как 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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...