MemberExpression属性未定义

时间:2014-11-26 18:40:01

标签: c# .net expression-trees

我需要帮助。 我有两个类:实体和模型。他们的代码如下。

public class TestEntityForSerialize
{
    public String FIO { get; set; }
    public DateTime Birthday { get; set; }
    public String Name { get; set; }
}

[DataContract]
public class TestModelForSerialize
{
    [DataMember]
    public String FIO { get; set; }
    [DataMember]
    public DateTime Birthday { get; set; }
    [DataMember(Name = "Name")]
    public String BigName { get; set; }
    public Int32 Age { get; set; }
}

主要任务是以编程方式将任何Func<TestModelForSerialize, Boolean>转换为Func <TestEntityForSerialize, Boolean>。我的决定是使用表达式树。我将ExpressionVisitor用于迭代模型的表达式树的节点,并构造一个新的Expression with Entity作为参数。这些Func的通用参数在类中设置,保留了功能。

我通过重写VisitParameter方法成功转换了ParameterExpression,但我仍然坚持使用ExpressionVisitor后代的重写VisitMember方法。实际上我有代码: VisitMember覆盖:

    protected override Expression VisitMember(MemberExpression node)
    {            
        Expression e = base.VisitMember(node);
        MemberExpression me = e as MemberExpression;
        if (me != null)
        {
            String modelPropertyName = ((PropertyInfo)me.Member).Name;
            ParameterExpression pe = node.Expression as ParameterExpression;
            TModel m = Activator.CreateInstance<TModel>();
            PropertyInfo memberPI = GetEntityProperty(m, modelPropertyName);
            MemberExpression meToReturn = Expression.Property(Expression.Parameter(typeof(TEntity)), memberPI);

            return meToReturn;
        }
        else
        {
            return base.VisitMember(node);
        }
    }

VisitParameter覆盖:

    protected override Expression VisitParameter(ParameterExpression node)
    {
        ParameterExpression pe = base.VisitParameter(node) as ParameterExpression;
        if (pe.Type == typeof(TModel))
        {
            ParameterExpression ex = Expression.Parameter(typeof(TEntity), pe.Name);
            return ex;
        }
        else
        {
            return pe;
        }
    }

GetEntityProperty是TModel类的方法映射属性到TEntity类的属性。它使用DataContract和DataMember进行映射。

    protected PropertyInfo GetEntityProperty(TModel model, String propertyName)
    {
        PropertyInfo property = model.GetType().GetProperty(propertyName);
        if (property != null)
        {
            Attribute attr = property.GetCustomAttribute(typeof(DataMemberAttribute));
            if (attr != null)
            {
                String entityPropertyName = (((DataMemberAttribute)attr).Name != null ? ((DataMemberAttribute)attr).Name : propertyName);
                return typeof(TEntity).GetProperty(entityPropertyName);
            }
            else
            {
                throw new DataMemberAttributeNotFoundException();
            }
        }
        else
        {
            throw new MissingMemberException();
        }
    }

TestMethod是

    [TestMethod]
    public void TestVisitMemberShouldReplaceModelWithEntity()
    {
        ParameterExpression p = Expression.Parameter(typeof(TestModelForSerialize));
        Type tm = typeof(TestModelForSerialize);
        PropertyInfo birthdayProp = tm.GetProperty("FIO");
        Assert.IsNotNull(birthdayProp);
        MemberExpression me = Expression.Property(p, birthdayProp);
        VisitorForTests vft = new VisitorForTests();
        MemberExpression meResult = vft.VisitMemberForTest(me) as MemberExpression;
        Assert.IsInstanceOfType(meResult.Member, typeof(PropertyInfo));
    }

VisitorForTests是在课堂上调用受保护方法的类,我试图处理。它的方法:

    public Expression VisitMemberForTest(MemberExpression node)
    {
        return this.VisitMember(node);
    }

当我尝试调用VisitMember方法时,它会破坏第一行(&#34; Expression e = base.VisitMember(node);&#34;),抛出带有消息的ArgumentException:Property&#34; FIO& #34;没有在课程中定义&#34; TestEntityForSerialize&#34;。只有我能注意到的事情 - VisitMember尝试启动VisitParameter方法,并在得到它的结果后 - 粉碎。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

疑难杂症! 正如俄罗斯谚语所说的那样:“拯救人类正在拯救 - 这是男人自己的事业。”问题是 - 我试图使用带有错误参数的Expression。它应该提供TEntity的属性,我将提供TModel的属性。所以只需轻松改变VisitMember方法和Qawabanga!

    protected override Expression VisitMember(MemberExpression node)
    {            
        //Expression e = base.VisitMember(node); - I've commented this line
        MemberExpression me = node as MemberExpression;
        if (me != null)
        {
            String modelPropertyName = ((PropertyInfo)me.Member).Name;
            ParameterExpression pe = node.Expression as ParameterExpression;
            TModel m = Activator.CreateInstance<TModel>();
            PropertyInfo memberPI = GetEntityProperty(m, modelPropertyName);
            MemberExpression meToReturn = Expression.Property(Expression.Parameter(typeof(TEntity)), memberPI.Name);

            return base.VisitMember(meToReturn); //and changed this line
        }
        else
        {
            return base.VisitMember(node);
        }
    }

这很有效!