C#表达式比较
假设集合中有以下表达式:C#表达式比较,c#,lambda,C#,Lambda,假设集合中有以下表达式: var people = new List<Person> { new Person {FullName = "Some Dude", Age = 45}, new Person {FullName = "Another Dude", Age = 28}, new Person {FullName = "Some Other Dude", Age = 36} }; var filtered = people.Where(pe
var people = new List<Person>
{
new Person {FullName = "Some Dude", Age = 45},
new Person {FullName = "Another Dude", Age = 28},
new Person {FullName = "Some Other Dude", Age = 36}
};
var filtered = people.Where(person => person.Age > 28 && person.FullName.StartsWith("So"));
var narrowlyFiltered = people.Where(person => person.Age > 36 && person.FullName.StartsWith("Some"));
var people=新列表
{
新人{FullName=“某个花花公子”,年龄=45},
新人{FullName=“另一个花花公子”,年龄=28},
新人{FullName=“另一个花花公子”,年龄=36}
};
var filtered=people.Where(person=>person.Age>28&&person.FullName.StartsWith(“So”);
var nearlyfiltered=people.Where(person=>person.Age>36&&person.FullName.StartsWith(“Some”);
有没有办法比较这两个表达式,并在运行时推断第二个表达式是第一个表达式的子集?没有列举或其他任何东西。我只有表达式,我正在尝试找出这些表达式是否相交或包含彼此。如果可以枚举集合,可以先将元素放入
哈希集中,然后在其上运行:
HashSet hs=新的HashSet(已过滤);
HashSet hs2=新的HashSet(窄带过滤);
高铁发行量(高铁2)// 您必须将每个表达式分解为所有可能的继承类型(MethodCallExpression、ConditionalExpression等),然后并行执行每个分解并检查每个可能的参数。。。这将是一个有点长的代码。。。你可以从中获得灵感,看看
一旦实现了它,那么在这种情况下,您的规范就变成了
public class PersonNamedOlderThanSpecification : CompositeSpecification<Person>
{
private string name;
private int age;
public PersonNamedOlderThanSpecification(string name, int age)
{
this.name = name;
this.age = age;
}
public override bool IsSatisfiedBy(Person entity)
{
return (entity.Name.Contains(this.name)) && (entity.Age > age);
}
}
您可以尝试以下方法:
var people = new List<Person>
{
new Person {FullName = "Some Dude", Age = 45},
new Person {FullName = "Another Dude", Age = 28},
new Person {FullName = "Some Other Dude", Age = 36}
};
var filtered = people.Where(person => person.Age > 28 && person.FullName.StartsWith("So"));
var narrowlyFiltered = people.Where(person => person.Age > 36 && person.FullName.StartsWith("Some"));
var intersection = filtered.Intersect(narrowlyFiltered);
if (intersection != null)
{
if (intersection.Count() > 0)
{
//narrowlyFiltered is subset of filtered
}
}
var people=新列表
{
新人{FullName=“某个花花公子”,年龄=45},
新人{FullName=“另一个花花公子”,年龄=28},
新人{FullName=“另一个花花公子”,年龄=36}
};
var filtered=people.Where(person=>person.Age>28&&person.FullName.StartsWith(“So”);
var nearlyfiltered=people.Where(person=>person.Age>36&&person.FullName.StartsWith(“Some”);
var intersection=已过滤。intersection(窄带过滤);
if(交叉点!=null)
{
if(intersection.Count()>0)
{
//狭义过滤是过滤的子集
}
}
这完全取决于你如何衡量什么是相等的,在比较表达式时什么更重要等等。
例如,若您有完全不同的过滤器,那个么在实际执行之前,您不可能知道查询的差异
要完全控制比较,请创建一个具有某些属性的筛选器类,这些属性可用于筛选,然后使用该类(而不是访问者)生成表达式并进行比较。
您可以准备用于比较整数、整数对(范围)等的公共函数
我没有检查下面的代码,但这应该是一个好的开始
public class PersonFilter: IComparable<PersonFilter>
{
public int? MinAge { get; set; }
public int? MaxAge { get; set; }
public string NamePrefix { get; set; }
public Expression<Predicate<Person>> Filter
{
return people => people.Where(person => (!MinAge.HasValue || person.Age > MinAge.Value) &&
(!MaxAge.HasValue || person.Age < MaxAge.Value) &&
(string.IsNullOrEmpty(NamePrefix) || person.FullName.StartsWith(NamePrefix))
}
// -1 if this filter is filtering more than the other
public int CompareTo(PersonFilter other)
{
var balance = 0; // equal
if(MinAge.HasValue != other.MinAge.HasValue)
{
balance += MinAge.HasValue ? -1 : 1;
}
else if(MinAge.HasValue)
{
balance += MinAge.Value.CompareTo(other.MinAge.Value) ?
}
if(string.IsNullOrEmpty(NamePrefix) != string.IsNullOrEmpty(other.NamePrefix))
{
balance += string.IsNullOrEmpty(NamePrefix) ? -1 : 1;
}
else if(!string.IsNullOrEmpty(NamePrefix))
{
if(NamePrefix.StartsWith(other.NamePrefix))
{
balance -= 1;
}
else if(other.NamePrefix.StartsWith(NamePrefix))
{
balance += 1;
}
else
{
// if NamePrefix is the same or completely different let's assume both filters are equal
}
}
return balance;
}
public bool IsSubsetOf(PersonFilter other)
{
if(MinAge.HasValue != other.MinAge.HasValue)
{
if(other.MinAge.HasValue)
{
return false;
}
}
else if(MinAge.HasValue && MinAge.Value < other.MinAge.Value)
{
return false;
}
if(string.IsNullOrEmpty(NamePrefix) != string.IsNullOrEmpty(other.NamePrefix))
{
if(!string.IsNullOrEmpty(other.NamePrefix))
{
return false;
}
}
else if(!string.IsNullOrEmpty(NamePrefix))
{
if(!NamePrefix.StartsWith(other.NamePrefix))
{
return false;
}
}
return true;
}
}
公共类PersonFilter:i可比较
{
公共整数{get;set;}
公共int?MaxAge{get;set;}
公共字符串名称前缀{get;set;}
公共表达式过滤器
{
return people=>people.Where(person=>(!MinAge.HasValue | | person.Age>MinAge.Value)&&
(!MaxAge.HasValue | | person.Age
你是指结果,还是在所有情况下?是的,只要你不让表达式变成委托。没有合理复杂的方法可以做到这一点,不。但是,应该不难检测其中一个的结果是否是另一个的子集。是的,有一种方法。但这需要一些操作。你确定需要这样做吗?有没有方法可以确定在它被放在表达式之前?@ CasoSoFT和乔纳森认为我还没有枚举它。我只是定义了两个空格,并且我试图通过定义来确定一个空间是否包含另一个空间。谢谢!我刚才解释的很像这个。@夏普:你提出的算法决定了TW是否为TW。o表达是“字面上的”同样。但是,如果您将两个表达式中的一个封装到一个方法中,它将失败。@Sharped:从表达式内部的调用中出现循环的那一刻起,问题就开始出现了。这里所述的问题就是一个很好的例子。person.Age
=>MemberExpression在这两种情况下,都针对同一类型上的相同属性。person.Age>28和person.Age>36都是B
var people = new List<Person>
{
new Person {FullName = "Some Dude", Age = 45},
new Person {FullName = "Another Dude", Age = 28},
new Person {FullName = "Some Other Dude", Age = 36}
};
var filtered = people.Where(person => person.Age > 28 && person.FullName.StartsWith("So"));
var narrowlyFiltered = people.Where(person => person.Age > 36 && person.FullName.StartsWith("Some"));
var intersection = filtered.Intersect(narrowlyFiltered);
if (intersection != null)
{
if (intersection.Count() > 0)
{
//narrowlyFiltered is subset of filtered
}
}
public class PersonFilter: IComparable<PersonFilter>
{
public int? MinAge { get; set; }
public int? MaxAge { get; set; }
public string NamePrefix { get; set; }
public Expression<Predicate<Person>> Filter
{
return people => people.Where(person => (!MinAge.HasValue || person.Age > MinAge.Value) &&
(!MaxAge.HasValue || person.Age < MaxAge.Value) &&
(string.IsNullOrEmpty(NamePrefix) || person.FullName.StartsWith(NamePrefix))
}
// -1 if this filter is filtering more than the other
public int CompareTo(PersonFilter other)
{
var balance = 0; // equal
if(MinAge.HasValue != other.MinAge.HasValue)
{
balance += MinAge.HasValue ? -1 : 1;
}
else if(MinAge.HasValue)
{
balance += MinAge.Value.CompareTo(other.MinAge.Value) ?
}
if(string.IsNullOrEmpty(NamePrefix) != string.IsNullOrEmpty(other.NamePrefix))
{
balance += string.IsNullOrEmpty(NamePrefix) ? -1 : 1;
}
else if(!string.IsNullOrEmpty(NamePrefix))
{
if(NamePrefix.StartsWith(other.NamePrefix))
{
balance -= 1;
}
else if(other.NamePrefix.StartsWith(NamePrefix))
{
balance += 1;
}
else
{
// if NamePrefix is the same or completely different let's assume both filters are equal
}
}
return balance;
}
public bool IsSubsetOf(PersonFilter other)
{
if(MinAge.HasValue != other.MinAge.HasValue)
{
if(other.MinAge.HasValue)
{
return false;
}
}
else if(MinAge.HasValue && MinAge.Value < other.MinAge.Value)
{
return false;
}
if(string.IsNullOrEmpty(NamePrefix) != string.IsNullOrEmpty(other.NamePrefix))
{
if(!string.IsNullOrEmpty(other.NamePrefix))
{
return false;
}
}
else if(!string.IsNullOrEmpty(NamePrefix))
{
if(!NamePrefix.StartsWith(other.NamePrefix))
{
return false;
}
}
return true;
}
}