Moja odpowiedź brzmiała, jak używać gościa z ekspresji. (dzięki @ Alexei-levenkov za wskazanie tego).
Odpowiedź dla mojej konkretnej sytuacji była trochę inna niż dla uproszczonego przykładu, którego użyłem w pytaniu. Ale pod względem kompletności, tutaj był, jak to zrobiłem:
public class ResolveParameterVisitor : ExpressionVisitor
{
private readonly ParameterExpression _param;
private readonly object _value;
public ResolveParameterVisitor(ParameterExpression param, object value)
{
_param = param;
_value = value;
}
public Expression ResolveLocalValues(Expression exp)
{
return Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == _param.Type && node.Name == _param.Name
&& node.Type.IsSimpleType())
{
return Expression.Constant(_value);
}
return base.VisitParameter(node);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
var parameters = node.Parameters.Where(p => p.Name != _param.Name && p.Type != _param.Type).ToList();
return Expression.Lambda(Visit(node.Body), parameters);
}
}
Zauważ, że IsSimpleType jest rozszerzeniem pożyczyłem od this gist przez jonothanconway.
W mojej sytuacji chciałem zastąpić użycie złożonego typu. np .:
Expression<Func<Thing, int, bool>> test = (thing, num) => thing.AnIntProperty == num;
Więc zrobiłem nadpisanie metody VisitMember. To wciąż trwa, ale wygląda następująco:
protected override Expression VisitMember(MemberExpression m)
{
if (m.Expression != null
&& m.Expression.NodeType == ExpressionType.Parameter
&& m.Expression.Type == _param.Type && ((ParameterExpression)m.Expression).Name == _param.Name)
{
object newVal;
if (m.Member is FieldInfo)
newVal = ((FieldInfo)m.Member).GetValue(_value);
else if (m.Member is PropertyInfo)
newVal = ((PropertyInfo)m.Member).GetValue(_value, null);
else
newVal = null;
return Expression.Constant(newVal);
}
return base.VisitMember(m);
}
To rozwiąże tylko pole lub właściwość. Następnym krokiem może być dodanie obsługi metody (ale ponieważ mają same parametry, więc zajmie to więcej pracy ...)
EDYCJA: Powyższe rozwiązanie dla odwiedzających użytkowników nie obsługuje również przekazywania samego obiektu do wywołania metody. na przykład (x, thing) => x.DoSomething(thing)
, więc modyfikacja byłaby potrzebna, aby to zrobić.
możliwy duplikat [C# Linq vs. Currying] (http://stackoverflow.com/questions/8826266/c-sharp-linq-vs-currying) –
podczas gdy głosowałem, że to dup, to pytanie może być w rzeczywistości inne . Może szukasz sposobu użycia gościa ekspresyjnego do zastąpienia argumentu wartością? (coś podobnego do [tego] (http://stackoverflow.com/questions/11164009/using-a-linq-expressionvisitor-to-replace-primitive-parameters-with-property-ref)) –
Nie całkiem. Chcę pracować z wyrażeniami. Myślę, że jest bliższa [this] (http://stackoverflow.com/questions/11159697/replace-parameter-in-lambda-expression) lub [this] (http://stackoverflow.com/questions/5631070/currying -expressions-in-c-sharp) –