我正在基于一些参数在CustomType上生成一个动态表达式。代码如下:
ParameterExpression parameter = Expression.Parameter(typeof(CustomType), "x");
MemberExpression idMember = Expression.Property(parameter, "CustomProperty");
当我从类型CustomType更改为接口ICustomType时,它因抛出错误'未为类型'ICustomType'定义实例属性'CustomProperty'而停止工作 。如何解决?
答案 0 :(得分:1)
没有最小的可验证示例,我们不能确定问题出在哪里,但是从您的示例代码中,我得出以下结论:
interface ICustomType
{
int CustomProperty { get; set; }
}
class CustomType : ICustomType
{
public int CustomProperty { get; set; }
}
现在,当我调用您的示例代码时,一切都会按预期运行
ParameterExpression parameter = Expression.Parameter(typeof(CustomType), "x");
MemberExpression idMember = Expression.Property(parameter, "CustomProperty");
此外,当我将类型更改为ICustomType
时,它仍然可以正常工作。
ParameterExpression parameter = Expression.Parameter(typeof(ICustomType), "x");
MemberExpression idMember = Expression.Property(parameter, "CustomProperty");
但是,如果我从CustomProperty
中删除了ICustomType
的声明,则会出现以下错误:
未为类型“ ICustomType”定义实例属性“ CustomProperty”
因此,这使我相信您的接口不包含CustomProperty
的声明。如果将其添加到界面中,则您的代码应该可以正常工作。
答案 1 :(得分:0)
使用表达式时,常见的任务是将某些节点替换为其他节点。例如,您可以像在answer中那样替换ParameterExpression
。我相信OP使用了类似的参数替换器,并且忘记了也替换了MemberExpression
。
如果替换表达式的参数,则原始MemberExpression
可能不是新的参数类型。例如。 CustomType.CustomProperty
的成员表达式将无法处理ICustomType.CustomProperty
。
如果我的理论正确,那么OP也必须替换某些MemberExpression
实例。以下表达式访问者可以解决这个问题:
public class ParameterReplacerVisitor : ExpressionVisitor
{
private readonly Type newType;
private Dictionary<ParameterExpression, ParameterExpression> parametersToReplace;
public ParameterReplacerVisitor(Type newType)
{
this.newType = newType;
}
public LambdaExpression Convert(LambdaExpression expression)
{
parametersToReplace = expression.Parameters
.Where(p => ShouldReplace(p.Type))
.ToDictionary(p => p, p => Expression.Parameter(newType, p.Name));
return (LambdaExpression)Visit(expression);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
var parameters = node.Parameters.Select(GetNewParameter);
return Expression.Lambda(Visit(node.Body), parameters);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return base.VisitParameter(GetNewParameter(node));
}
protected override Expression VisitMember(MemberExpression node)
{
if (ShouldReplace(node.Member.DeclaringType))
{
var targetProperty = GetNewProperty(node.Member);
node = Expression.MakeMemberAccess(Visit(node.Expression), targetProperty);
}
return base.VisitMember(node);
}
private MemberInfo GetNewProperty(MemberInfo member)
{
return newType.GetProperty(member.Name) ?? throw new ArgumentException(
$"Property '{member.Name}' is not defined for type '{newType.Name}'"
);
}
private bool ShouldReplace(Type type) => newType.IsAssignableFrom(type);
private ParameterExpression GetNewParameter(ParameterExpression parameter)
{
parametersToReplace.TryGetValue(parameter, out var newParameter);
return newParameter ?? parameter;
}
}
Expression<Func<Derived, string>> derived = t => t.A;
var lessDerived = derived.ToLessDerived<Derived, IBase, string>();
var d = lessDerived.Compile();
var result = d.Invoke(new Base());
以及扩展方法:
public static Expression<Func<TLess, TValue>> ToLessDerived<TClass, TLess, TValue>(this Expression<Func<TClass, TValue>> expression)
{
var visitor = new ParameterReplacerVisitor(typeof(TLess));
return (Expression<Func<TLess, TValue>>)visitor.Convert(expression);
}
对我来说,这解决了OP要求的完全相同的错误类型。