如何从表达式中获取 属性 名称和比较值?
How do I grab the Property name and compared value from an expression?
我们在工作中使用的过滤器是一种类型
Expression < Func < T, bool > >
我们将其与以下方法一起使用:
Tuple< string, string, object > SplitFilter< People >(x => x.SurName == "Smith");
我需要创建一个方法,将 Expression< Func < T, bool >> 作为参数,如上所示,并将其分解为 3 个值,一个字符串 "SurName" 用于 属性,一个字符串“==”表示相等比较,字符串"Smith"也表示被比较的值。
我设法从中取出了字符串 "SurName",但我终生无法弄清楚如何确定比较类型(相等)或比较值 ("Smith")
取自此处:https://www.codeproject.com/Questions/322211/Parsing-a-linq-expression
static readonly List<int> data = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
static IEnumerable<int> SelectData(Expression<Predicate<int>> selector)
{
ParameterExpression param = (ParameterExpression)selector.Parameters[0];
BinaryExpression operation = (BinaryExpression)selector.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
//...
return from d in data where selector.Compile()(d) select d;
}
static void Main(string[] args)
{
Console.WriteLine("data = {0}", string.Join(",", SelectData(d=>d>4)));
}
Decomposed expression: d => d GreaterThan 4
data = 5,6,7,8,9
前几天成功了。最终目标实际上是对这些值进行哈希处理,这样我们就可以从每个过滤器中得到一个哈希值。对于以后的人,我最后是这样分解的:
private int HashFilter<T>( Expression<Func<T, bool>> filter ) {
var param = filter.Parameters[0];
var operation = filter.Body as BinaryExpression;
var leftParameter = operation.Left as ParameterExpression;
var leftIndex = operation.Left as MemberExpression;
var type = operation.Left.GetType().FullName;
var rightConstant = operation.Right as ConstantExpression;
object result;
if ( rightConstant == null ) {
var rightMember = operation.Right as MemberExpression;
result = Expression.Lambda( rightMember ).Compile().DynamicInvoke();
}
else {
result = rightConstant.Value;
}
var value = result as string;
var leftHashCode = leftParameter != null ? leftParameter.Name.GetStableHashCode() : leftIndex.Member.Name.GetStableHashCode();
var operationHashCode = operation.NodeType.ToString().GetStableHashCode();
unchecked {
if ( value != null ) {
return leftHashCode | operationHashCode | value.GetStableHashCode();
}
else {
return leftHashCode | operationHashCode | result.GetHashCode();
}
}
}
使用 GetStableHashCode 作为以下扩展 hasing 算法(因为散列字符串使用引用,所以 "Hi".GetHashCode() == "Hi".GetHashCode() 永远不会评估为真,但是这个 GetStableHashCode 会。
public static int GetStableHashCode( this string str ) {
unchecked {
int hash1 = (5381 << 16) + 5381;
int hash2 = hash1;
for ( int i = 0; i < str.Length; i += 2 ) {
hash1 = ((hash1 << 5) + hash1) ^ str[i];
if ( i == str.Length - 1 )
break;
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
}
return hash1 + (hash2 * 1566083941);
}
}
我们在工作中使用的过滤器是一种类型
Expression < Func < T, bool > >
我们将其与以下方法一起使用:
Tuple< string, string, object > SplitFilter< People >(x => x.SurName == "Smith");
我需要创建一个方法,将 Expression< Func < T, bool >> 作为参数,如上所示,并将其分解为 3 个值,一个字符串 "SurName" 用于 属性,一个字符串“==”表示相等比较,字符串"Smith"也表示被比较的值。
我设法从中取出了字符串 "SurName",但我终生无法弄清楚如何确定比较类型(相等)或比较值 ("Smith")
取自此处:https://www.codeproject.com/Questions/322211/Parsing-a-linq-expression
static readonly List<int> data = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
static IEnumerable<int> SelectData(Expression<Predicate<int>> selector)
{
ParameterExpression param = (ParameterExpression)selector.Parameters[0];
BinaryExpression operation = (BinaryExpression)selector.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
//...
return from d in data where selector.Compile()(d) select d;
}
static void Main(string[] args)
{
Console.WriteLine("data = {0}", string.Join(",", SelectData(d=>d>4)));
}
Decomposed expression: d => d GreaterThan 4
data = 5,6,7,8,9
前几天成功了。最终目标实际上是对这些值进行哈希处理,这样我们就可以从每个过滤器中得到一个哈希值。对于以后的人,我最后是这样分解的:
private int HashFilter<T>( Expression<Func<T, bool>> filter ) {
var param = filter.Parameters[0];
var operation = filter.Body as BinaryExpression;
var leftParameter = operation.Left as ParameterExpression;
var leftIndex = operation.Left as MemberExpression;
var type = operation.Left.GetType().FullName;
var rightConstant = operation.Right as ConstantExpression;
object result;
if ( rightConstant == null ) {
var rightMember = operation.Right as MemberExpression;
result = Expression.Lambda( rightMember ).Compile().DynamicInvoke();
}
else {
result = rightConstant.Value;
}
var value = result as string;
var leftHashCode = leftParameter != null ? leftParameter.Name.GetStableHashCode() : leftIndex.Member.Name.GetStableHashCode();
var operationHashCode = operation.NodeType.ToString().GetStableHashCode();
unchecked {
if ( value != null ) {
return leftHashCode | operationHashCode | value.GetStableHashCode();
}
else {
return leftHashCode | operationHashCode | result.GetHashCode();
}
}
}
使用 GetStableHashCode 作为以下扩展 hasing 算法(因为散列字符串使用引用,所以 "Hi".GetHashCode() == "Hi".GetHashCode() 永远不会评估为真,但是这个 GetStableHashCode 会。
public static int GetStableHashCode( this string str ) {
unchecked {
int hash1 = (5381 << 16) + 5381;
int hash2 = hash1;
for ( int i = 0; i < str.Length; i += 2 ) {
hash1 = ((hash1 << 5) + hash1) ^ str[i];
if ( i == str.Length - 1 )
break;
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
}
return hash1 + (hash2 * 1566083941);
}
}