私の答えは、式ビジターを使用することでした。(指摘してくれた@Alexei-levenkovに感謝します)。
私の特定の状況に対する答えは、質問で使用した単純化された例とは少し異なりました。しかし、完全を期すために、これが私がやった方法です:
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);
}
}
IsSimpleType は、jonothanconwayによってこの要点から借用した拡張機能であることに注意してください。
私の状況では、複合型の使用を置き換えたいと考えていました。例えば:
Expression<Func<Thing, int, bool>> test = (thing, num) => thing.AnIntProperty == num;
そこで、VisitMember メソッドをオーバーライドしました。これはまだ進行中の作業ですが、次のようになります。
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);
}
これは、フィールドまたはプロパティのみを解決します。次のステップは、メソッドのサポートを追加することかもしれません (ただし、メソッド自体にパラメーターがあるため、さらに作業が必要になります...)
編集: 上記のメンバー ビジター ソリューションは、オブジェクト自体をメソッド呼び出しに渡すこともサポートしません。たとえば(x, thing) => x.DoSomething(thing)
、そのためにも変更が必要になります。