Основная идея аналогична объединению деревьев выражений для повторного использования в запросах Linq.
В моей ситуации у меня две модели и DTO:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public Extra Extra { get; set; }
}
public class Extra
{
public int Id { get; set; }
public string Text { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public ExtraDto Extra { get; set; }
}
public class ExtraDto
{
public int Id { get; set; }
public string Text { get; set; }
}
и выражения:
Expression<Func<Extra, ExtraDto>> extraSelector = o => new ExtraDto
{
Id = o.Id,
Text = o.Text
};
Expression<Func<User, UserDto>> userSelector = o => new UserDto
{
Id = o.Id,
Name = o.Name
};
Теперь я хотел бы добавить " extraSelector
в userSelector
. Псевдокод выглядит так:
var selectorExpression = userSelector.Append(user => user.Extra, extraSelector);
Context.Users.Select(selectorExpression).ToList();
Окончательное выражение будет следующим:
Expression<Func<User, UserDto>> userSelector = o => new UserDto
{
Id = o.Id,
Name = o.Name,
Extra = new ExtraDto
{
Id = o.Extra.Id,
Text = o.Extra.Text
}
};
Я попытался использовать ExpressionVisitor
, но не повезло.
Помимо "слияния" двух селекторов, вы должны вставить "путь" o => o.Extra
в extraSelector
и создать новое "выражение привязки" для свойства Extra
of UserDto
.
На самом деле, я играю с такими сценариями в рамках этого проекта, где я пытался абстрагироваться от такого типа выражения. Тогда ваше "слияние" будет выглядеть так:
userSelector = extraSelector.Translate()
.Cross<User>(o => o.Extra)
.Apply(o => o.Extra, userSelector);
Метод расширения Translate
- это всего лишь небольшой помощник, чтобы использовать вывод типа, Cross
inserts o => o.Extra
в extraSelector
, Apply
создает "выражение привязки" для свойства Extra
of UserDto
и, наконец, объединяет результат с userSelector
.