Деревья выражений 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();
вот именно то, что я делаю:
- создал
CallSiteBinder
который получает значение динамического свойстваName
динамического объекта, переданного в качестве аргумента - создал
CallSiteBinder
который получает значение динамического свойстваSurname
динамического объекта, переданного в качестве аргумента - вызывается метод
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 });