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;
    }
}