Деревья выражений c динамическим параметром

Я хочу преобразовать это:

Func<dynamic, object> myFunc = t => return t.Name + " " + t.Surname;

в дерево выражений.

вот что я придумал:

ParameterExpression target = ExpressionParameter(typeof(dynamic), "target");
ParameterExpression result = ExpressionParameter(typeof(object), "result");
BlockExpression block = Expression.Block(
     new [] { result },
     Expression.Assign(
           result,
           Expression.Add(
                 Expression.Add(
                      Expression.Property(target, "Name"),
                      Expression.Constant(" ", typeof(string))
                 ),
                 Expression.Property(target, "Surname")
           )
     )
);
Func<dynamic, object> myFunc = Expression.Lambda<dynamic, object>>(block, target).Compile();

однако компилятору не нравится typeof(dynamic) и я тебя понимаю. dynamic - это не тип, это object в сущности.

поэтому я продолжил изменять ParameterExpression:

ParameterExpression target = ExpressionParameter(typeof(object), "target");

теперь код компилируется, но есть проблема во время выполнения.

Я пытаюсь получить значение собственность Name of target, который может иметь смысл, если объект был dynamic.

но поскольку target считается типа object, выражение выдает ошибку, сообщая мне Name не существует как свойство.

есть ли выражение для извлечения динамического свойства?

1 ответов


для тех, кто заинтересован или был заинтересован в решении:

ParameterExpression target = Expression.Parameter(typeof(object), "target");
ParameterExpression result = Expression.Parameter(typeof(object), "result");

CallSiteBinder getName = Binder.GetMember(
   CSharpBinderFlags.None, "Name", typeof(Program),
   new CSharpArgumentInfo[] {
       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
   }
);

CallSiteBinder getSurname= Binder.GetMember(
   CSharpBinderFlags.None, "Surname", typeof(Program),
   new CSharpArgumentInfo[] {
       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
   }
);

BlockExpression block = Expression.Block(
    new[] { result },
    Expression.Assign(
        result,
        Expression.Call(typeof(string).GetMethod("Concat", new Type[] { typeof(object[]) }),
                        Expression.NewArrayInit(typeof(object),
                             Expression.Dynamic(getName, typeof(object), target),
                             Expression.Constant(" ", typeof(object)),
                             Expression.Dynamic(getSurname, typeof(object), target)
                        )
       )
    )
);

Func<dynamic, object> myFunc = Expression.Lambda<Func<dynamic, object>>(block, target).Compile();

вот именно то, что я делаю:

  1. создал CallSiteBinder который получает значение динамического свойства Name динамического объекта, переданного в качестве аргумента
  2. создал CallSiteBinder который получает значение динамического свойства Surname динамического объекта, переданного в качестве аргумента
  3. вызывается метод string.Concat(params object[] args). Для этого мне нужно отправить свои аргументы как массив object. Я создаю массив со значениями getName, " " и getSurname.

я использовал следующий ответ в качестве руководства и ссылки:

C# 4 "динамический" в деревьях выражений

с вышеуказанным подходом можно было бы сделать что-то вроде этого:

dynamic person = new ExpandoObject();
person.Name = "Matt";
person.Surname = "Smith";

object value = myFunc(person);
Console.WriteLine(value); //Will print out "Matt Smith"

//Internally it just calls:
//string.Concat(new object[] { person.Name, " ", person.Surname });