Выражение для создания экземпляра с инициализатором объекта
Есть ли способ создать экземпляр объекта с инициализатором объекта с помощью дерева выражений? Я имею в виду создание дерева выражений для создания этой лямбда:
// my class
public class MyObject {
public bool DisplayValue { get; set; }
}
// my lambda:
var lambda = (Func<bool, MyObject>)
(displayValue => new MyObject { DisplayValue = displayValue });
Как я могу создать эту лямбду с деревом выражений?
UPDATE:
Я попробовал сам и напишу следующий код:
public static Func<bool, dynamic> Creator;
static void BuildLambda() {
var expectedType = typeof(MyObject);
var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
var ctor = Expression.New(expectedType);
var local = Expression.Parameter(expectedType, "obj");
var displayValueProperty = Expression.Property(ctor, "DisplayValue");
var returnTarget = Expression.Label(expectedType);
var returnExpression = Expression.Return(returnTarget,local, expectedType);
var returnLabel = Expression.Label(returnTarget, Expression.Default(expectedType));
var block = Expression.Block(
new[] { local },
Expression.Assign(local, ctor),
Expression.Assign(displayValueProperty, displayValueParam),
Expression.Return(Expression.Label(expectedType), local, expectedType),
returnExpression,
returnLabel
);
Creator =
Expression.Lambda<Func<bool, dynamic>>(block, displayValueParam)
.Compile();
}
Но это вызывает следующую ошибку:
Невозможно перейти к undefined label ''.
Могут ли все помочь мне?
Ответы
Ответ 1
Чтобы представить инициализаторы объектов в выражении, вы должны использовать Expression.MemberInit()
:
Expression<Func<bool, MyObject>> BuildLambda() {
var createdType = typeof(MyObject);
var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
var ctor = Expression.New(createdType);
var displayValueProperty = createdType.GetProperty("DisplayValue");
var displayValueAssignment = Expression.Bind(
displayValueProperty, displayValueParam);
var memberInit = Expression.MemberInit(ctor, displayValueAssignment);
return
Expression.Lambda<Func<bool, MyObject>>(memberInit, displayValueParam);
}
Чтобы убедиться, что это действительно делает то, что вы хотите, вы можете вызвать ToString()
в созданном выражении. В этом случае вывод будет таким, как ожидалось:
displayValue => new MyObject() {DisplayValue = displayValue}
Ответ 2
Наконец, я нашел свой ответ:
public static Func<bool, dynamic> Creator;
static void BuildLambda() {
var expectedType = typeof(MyObject);
var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
var ctor = Expression.New(expectedType);
var local = Expression.Parameter(expectedType, "obj");
var displayValueProperty = Expression.Property(local, "DisplayValue");
var returnTarget = Expression.Label(expectedType);
var returnExpression = Expression.Return(returnTarget,local, expectedType);
var returnLabel = Expression.Label(returnTarget, Expression.Default(expectedType));
var block = Expression.Block(
new[] { local },
Expression.Assign(local, ctor),
Expression.Assign(displayValueProperty, displayValueParam),
/* I forgot to remove this line:
* Expression.Return(Expression.Label(expectedType), local, expectedType),
* and now it works.
* */
returnExpression,
returnLabel
);
Creator =
Expression.Lambda<Func<bool, dynamic>>(block, displayValueParam)
.Compile();
}
UPDATE:
Пока он работает нормально, но @svick обеспечивает лучший и более короткий способ в своем ответе, который я бы искал: MemberInit
. См. Ответ @svick.