Cha*_*ell 7 c# expression-trees
我试图在不使用.Compile()的情况下从表达式树中获取对象的值时遇到问题
对象很简单.
var userModel = new UserModel { Email = "John@Doe.com"};
Run Code Online (Sandbox Code Playgroud)
给我问题的方法看起来像这样.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我正在运行的测试非常简单
[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 );
}
Run Code Online (Sandbox Code Playgroud)
[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 );
}
Run Code Online (Sandbox Code Playgroud)
我应该注意改变
var val = (expression.Member as FieldInfo).GetValue((expression.Expression as ConstantExpression).Value);
Run Code Online (Sandbox Code Playgroud)
至
var val = Expression.Lambda( expression ).Compile().DynamicInvoke().ToString();
Run Code Online (Sandbox Code Playgroud)
将允许测试通过,但是此代码需要在iOS上运行,因此无法使用 .Compile()
TLDR;
只要你没有使用Emit或反射就可以使用反射Compile.在该问题中,正在提取该值FieldInfo,但未提取该值PropertyInfo.确保你可以同时获得.
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();
}
Run Code Online (Sandbox Code Playgroud)
冗长的版本
所以评论指出了我正确的方向.获得PropertyInfo后我有点挣扎,但最后,这就是我想出的.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,如果Member.NodeType是a Parameter,那么我将把它用作SQL字段.[FieldName]
否则,我正在使用它作为SQL参数@FieldName......后退我知道.
如果Member.NodeType不是参数,那么我检查它是模型Field还是模型Property.从那里,我得到适当的值,并将键/值对添加到字典中以用作SQL参数.
最终的结果是我构建了一个看起来像的字符串
SELECT * FROM TableName WHERE
[FieldName] = @FieldName
Run Code Online (Sandbox Code Playgroud)
然后传递参数
var parameters = new Dictionary<string, object> Parameters;
parameters.Add("@FieldName", "The value of the field");
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9606 次 |
| 最近记录: |