如何从MemberExpression得到属性值不.Compile()? [英] How to get Property Value from MemberExpression without .Compile()?

查看:129
本文介绍了如何从MemberExpression得到属性值不.Compile()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在试图让一个对象的值了表达式树的问题,而没有使用.Compile()



对象是相当简单的。

  VAR的usermodel =新的usermodel {EMAIL =John@Doe.com}; 



给我的问题的方法是这样的。

 私人无效VisitMemberAccess(MemberExpression表达,MemberExpression左)
{
VAR键=留下!= NULL? left.Member.Name:expression.Member.Name;
如果(expression.Expression.NodeType.ToString()==参数)
{
//添加字符串键
_strings.Add(的String.Format([ {0}]键));
}
,否则
{
//添加字符串参数
_strings.Add(的String.Format(@ {0},键));

//潜在的NullReferenceException
VAR VAL =(expression.Member的字段信息).GetValue((expression.Expression为常量表达式)。价值);

//添加参数值
Parameters.Add(@+键,VAL);
}
}



我跑这些测试很简单

  [测试] // PASS 
公共无效ShouldVisitExpressionByGuidObject()
{
//设置
VAR ID =新的GUID(CCAF57D9-88A4-4DCD-87C7-DB875E0D4E66);
常量字符串expectedString =[ID] = @Id;
变种expectedParameters =新词典<字符串对象> {{@Id,ID}};

//执行
VAR actualExpression = testexpression与<&的usermodel GT;(U => u.Id == ID);
VAR actualParameters = actualExpression.Parameters;
VAR actualString = actualExpression.WhereExpression;

//测试
Assert.AreEqual(expectedString,actualString);
CollectionAssert.AreEquivalent(expectedParameters,actualParameters);
}





  [测试] // FAIL [System.NullReferenceException:未将对象引用设置到对象的实例] 
公共无效ShouldVisitExpressionByStringObject()
{
//设置
变种expectedUser =新的usermodel {EMAIL =john@doe.com};

常量字符串expectedString =[邮件] = @Email;
变种expectedParameters =新词典<字符串对象> {{@Email,expectedUser.Email}};

//执行
VAR actualExpression = testexpression与<&的usermodel GT;(U => u.Email == expectedUser.Email);
VAR actualParameters = actualExpression.Parameters;
VAR actualString = actualExpression.WhereExpression;

//断言
Assert.AreEqual(expectedString,actualString);
CollectionAssert.AreEquivalent(expectedParameters,actualParameters);
}






我要指出,改变

  VAR VAL =(expression.Member的字段信息).GetValue((expression.Expression为常量表达式)。价值); 



 <$ 。C $ C> VAR VAL = Expression.Lambda(表达).Compile()DynamicInvoke()的ToString(); 



将允许测试通过,然而,这代码需要iOS上运行,并且因此不能使用 .Compile()


解决方案

TLDR ; 结果
反思是好的,只要使用,你使用的不是的Emit 编译。在的问题,被提取的值字段信息,但它没有被提取的PropertyInfo 。确保你可以同时获得。

  IF((expression.Member为的PropertyInfo)!= NULL)
$ { b $ b //从属性

}
,否则的值,如果((expression.Member的字段信息)!= NULL)
{
//获取从外地
值}
,否则
{
抛出新InvalidMemberException();
}






<强>啰嗦版



所以评论中指出我朝着正确的方向。我得到的PropertyInfo稍有挣扎,但最终,这里就是我想出了。

 私人无效VisitMemberAccess(MemberExpression表达,MemberExpression左)
{
//为了保护案例键/值对之间,我们总是希望使用表达式的左侧。
//因此,如果不为空,则表达实际上是离开了。
//这样做可以确保我们的'key`参数名和数据库字段之间的匹配
VAR键=留下!= NULL? left.Member.Name:expression.Member.Name;

//如果是的NodeType一个`Parameter`,我们要添加的密钥作为数据库字段名称我们的字符串集合
//否则,我们要添加的密钥作为DB参数我们的字符串集合
如果(expression.Expression.NodeType.ToString()==参数)
{
_strings.Add(的String.Format([{0}] 键));
}
,否则
{
_strings.Add(的String.Format(@ {0},键));

//如果键被添加为DB参数,那么我们也必须参数键/值对添加到集合
//因为我们正在关闭模型这应该只包含属性或字段,
//对象应该只有两种选择。的PropertyInfo或字段信息......让我们来提取相应价值
VAR值=新的对象();
如果((expression.Member为的PropertyInfo)!= NULL)
{
VAR EXP =(MemberExpression)expression.Expression;
VAR常数=(常量表达式)exp.Expression;
VAR fieldInfoValue =((字段信息)exp.Member).GetValue(constant.Value);
值=((的PropertyInfo)expression.Member).GetValue(fieldInfoValue,NULL);

}
,否则如果((expression.Member的字段信息)!= NULL)
{
变种的FieldInfo = expression.Member的字段信息;
VAR常量表达式= expression.Expression为常量表达式;
如果(字段信息= NULL&安培;!常量表达式= NULL)
{
值= fieldInfo.GetValue(constantExpression.Value);
}
}
,否则
{
抛出新InvalidMemberException();
}

//添加参数键/值对。
Parameters.Add(@+键,值);
}
}

从本质上讲,如果会员.NodeType 参数,那么我会使用它作为一个SQL场。 [字段名]



否则,我使用它作为一个SQL参数 @FieldName ...向后我知道了。



如果在 Member.NodeType 不是参数,然后我检查,看看它要么模型字段或模型属性。从那里,我得到了适当的值,键/值对添加到字典用作SQL参数。



最终的结果是,我建立一个字符串这看起来像



<预类=郎-SQL prettyprint-覆盖> SELECT * FROM表名WHERE
[字段名] = @FieldName

然后参数传递





  VAR参数=新词典与LT;字符串对象>参数; 
parameters.Add(@字段名,字段的值);


I'm having issues trying to get the value of an object out of the Expression Tree without using .Compile()

The object is quite simple.

var userModel = new UserModel { Email = "John@Doe.com"};

The method giving me issues looks like this.

private void VisitMemberAccess(MemberExpression expression, MemberExpression left)
{
    var key = left != null ? left.Member.Name : expression.Member.Name;
    if (expression.Expression.NodeType.ToString() == "Parameter")
    {
        // add the string key
        _strings.Add(string.Format("[{0}]", key));
    }
    else
    {
        // add the string parameter
        _strings.Add(string.Format("@{0}", key));

        // Potential NullReferenceException
        var val = (expression.Member as FieldInfo).GetValue((expression.Expression as ConstantExpression).Value);

        // add parameter value
        Parameters.Add("@" + key, val);
    }
}

The tests I'm running are quite simple

[Test]  // PASS
public void ShouldVisitExpressionByGuidObject ()
{
    // Setup
    var id = new Guid( "CCAF57D9-88A4-4DCD-87C7-DB875E0D4E66" );
    const string expectedString = "[Id] = @Id";
    var expectedParameters = new Dictionary<string, object> { { "@Id", id } };

    // Execute
    var actualExpression = TestExpression<UserModel>( u => u.Id == id );
    var actualParameters = actualExpression.Parameters;
    var actualString = actualExpression.WhereExpression;

    // Test
    Assert.AreEqual( expectedString, actualString );
    CollectionAssert.AreEquivalent( expectedParameters, actualParameters );
}

[Test]  // FAIL [System.NullReferenceException : Object reference not set to an instance of an object.]
public void ShouldVisitExpressionByStringObject ()
{
    // Setup
    var expectedUser = new UserModel {Email = "john@doe.com"};

    const string expectedString = "[Email] = @Email";
    var expectedParameters = new Dictionary<string, object> { { "@Email", expectedUser.Email } };

    // Execute
    var actualExpression = TestExpression<UserModel>( u => u.Email == expectedUser.Email );
    var actualParameters = actualExpression.Parameters;
    var actualString = actualExpression.WhereExpression;

    // Assert
    Assert.AreEqual( expectedString, actualString );
    CollectionAssert.AreEquivalent( expectedParameters, actualParameters );
}


I should note that changing

var val = (expression.Member as FieldInfo).GetValue((expression.Expression as ConstantExpression).Value);

to

var val = Expression.Lambda( expression ).Compile().DynamicInvoke().ToString();

will allow the test to pass, however this code needs to run on iOS, and therefore can't use .Compile()

解决方案

TLDR;
Reflection is ok to use as long as you're not using Emit or Compile. In the question, the value is being extracted for FieldInfo, but it is not being extracted for PropertyInfo. Make sure you can get BOTH.

if ((expression.Member as PropertyInfo) != null)
{
    // get the value from the PROPERTY

}
else if ((expression.Member as FieldInfo) != null)
{
    // get the value from the FIELD
}
else
{
    throw new InvalidMemberException();
}


Long-winded version

So the comments pointed me in the right direction. I struggled slightly with getting the PropertyInfo, but in the end, here's what I came up with.

private void VisitMemberAccess(MemberExpression expression, MemberExpression left)
{
    // To preserve Case between key/value pairs, we always want to use the LEFT side of the expression.
    // therefore, if left is null, then expression is actually left. 
    // Doing this ensures that our `key` matches between parameter names and database fields
    var key = left != null ? left.Member.Name : expression.Member.Name;

    // If the NodeType is a `Parameter`, we want to add the key as a DB Field name to our string collection
    // Otherwise, we want to add the key as a DB Parameter to our string collection
    if (expression.Expression.NodeType.ToString() == "Parameter")
    {
        _strings.Add(string.Format("[{0}]", key));
    }
    else
    {
        _strings.Add(string.Format("@{0}", key));

        // If the key is being added as a DB Parameter, then we have to also add the Parameter key/value pair to the collection
        // Because we're working off of Model Objects that should only contain Properties or Fields,
        // there should only be two options. PropertyInfo or FieldInfo... let's extract the VALUE accordingly
        var value = new object();
        if ((expression.Member as PropertyInfo) != null)
        {
            var exp = (MemberExpression) expression.Expression;
            var constant = (ConstantExpression) exp.Expression;
            var fieldInfoValue = ((FieldInfo) exp.Member).GetValue(constant.Value);
            value = ((PropertyInfo) expression.Member).GetValue(fieldInfoValue, null);

        }
        else if ((expression.Member as FieldInfo) != null)
        {
            var fieldInfo = expression.Member as FieldInfo;
            var constantExpression = expression.Expression as ConstantExpression;
            if (fieldInfo != null & constantExpression != null)
            {
                value = fieldInfo.GetValue(constantExpression.Value);
            }
        }
        else
        {
            throw new InvalidMemberException();
        }

        // Add the Parameter Key/Value pair.
        Parameters.Add("@" + key, value);
    }
}

Essentially, if the Member.NodeType is a Parameter, then I'm going to use it as a SQL Field. [FieldName]

Otherwise, I'm using it as a SQL Parameter @FieldName ... backwards I know.

If the Member.NodeType is NOT a Parameter, then I check to see if it's either a Model Fieldor a Model Property. From there, I get the appropriate value, and add the Key/Value pair to a Dictionary to be used as SQL Parameters.

The end result is that I build a string that looks something like

SELECT * FROM TableName WHERE
[FieldName] = @FieldName

Then the parameters are passed

var parameters = new Dictionary<string, object> Parameters;
parameters.Add("@FieldName", "The value of the field");

这篇关于如何从MemberExpression得到属性值不.Compile()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆