Мой вопрос очень похож на следующие два вопроса, но у меня есть дополнительное требование, которое они не удовлетворяют.Как установить значение из выражения для вложенных уровней глубины?
- How to set property value using Expressions?
- How set value a property selector Expression<Func<T,TResult>>
Так же, как эти вопросы, у меня есть Expression<Func<TEntity, TProperty>>
, где я хочу, чтобы установить значение указанного свойства. И эти решения работают отлично, если тело выражения имеет только один уровень глубины, например x => x.FirstName
, но они не работают вообще, если это тело глубже, например x => x.Parent.FirstName
.
Есть ли способ принять это более глубокое выражение и установить его значение? Мне не нужно очень надежное решение с отложенным выполнением, но мне нужно что-то, что я могу выполнить на объекте, и это будет работать, будь то уровень 1 или несколько уровней. Мне также необходимо поддерживать большинство типичных типов, которые вы ожидаете в базе данных (long
, int?
, string
, Decimal
, DateTime?
и т. Д., Хотя мне все равно, что более сложные вещи, такие как гео-типы).
Ради разговор, давайте говорить, что мы работаем с этими объектами, хотя предположить, что мы должны обрабатывать N уровней глубоко, а не только 1 или 2:
public class Parent
{
public string FirstName { get; set; }
}
public class Child
{
public Child()
{
Mom = new Parent(); // so we don't have to worry about nulls
}
public string FavoriteToy { get; set; }
public Parent Mom { get; set; }
}
и скажем, что это наш блок тест:
[TestFixture]
public class Tests
{
[Test]
public void MyTest()
{
var kid = new Child();
Expression<Func<Child, string>> momNameSelector = (ch => ch.Mom.FirstName);
Expression<Func<Child, string>> toyNameSelector = (ch => ch.FavoriteToy);
kid.ExecuteMagicSetter(momNameSelector, "Jane");
kid.ExecuteMagicSetter(toyNameSelector, "Bopp-It!");
Assert.That(kid.Mom.FirstName, Is.EqualTo("Jane"));
Assert.That(kid.FavoriteToy, Is.EqualTo("Bopp-It!"));
}
}
и наш метод расширения мы смотрим на (я не установил на нем необходимости быть метод расширения, но это кажется достаточно простым) будет выглядеть следующим образом:
public static TEntity ExecuteMagicSetter<TEntity, TProperty>(this TEntity obj, Expression<Func<TEntity, TProperty>> selector, TProperty value)
where TEntity : class, new() // I don't require this but I can allow this restriction if it helps
{
// magic
}
P.S. Эта версия кода была написана в редакторе SO - мои извинения за немые синтаксические проблемы, но это должно быть чертовски близко! #LockedDownWorkstationsSuck
Не имеет значения, насколько глубоко вложены ваши выражения-члены, до тех пор, пока выражение заканчивается в свойстве/поле. Затем с этим выражением вы можете добавить задание, и все готово. –
@JeffMercado Каждое решение из тех вопросов, которые я попытался, в конечном итоге имеет проблему использования отражения для вызова метода setter (в моем примере выше) объекта Parent, но с переданным в экземпляре объектом 'Child', так что во время выполнения есть несоответствие типа, которое терпит неудачу. Я чувствую, что недостающая магия либо рекурсивно, либо итеративно получает объекты дочернего объекта, а затем передает их методу setter. – Jaxidian
Ну, включите свои попытки в проблему. Проблема, которую вы описываете, не похожа на одну, связанную с вложенными выражениями. Если вы не генерируете эти синтаксические выражения вручную и не позволяете компилятору справиться с этим, оно должно быть действительным выражением в первую очередь. –