添加委托:添加两个Func <t,tresult> </t,tresult>时出现意外结果

时间:2014-07-22 09:04:40

标签: c# operators expression func

所以这是我在使用表达式和函数时观察到的奇怪行为。

public int Age { get; set; }
public EyeColor EyeColor { get; set; }
public int Weight { get; set; }

public Func<Person, bool> AgeAndEyesMatch
    {
        get { return IsPersonYoung().Compile() + PersonHasRightEyeColor().Compile(); }
    }

public Func<Person,bool> AgeAndWeightMatch
    {
        get { return IsPersonYoung().Compile() + IsPersonInShape().Compile(); }
    } 

private Expression<Func<Person, bool>> PersonHasRightEyeColor()
    {
        return person => person.EyeColor == EyeColor;
    }

private Expression<Func<Person, bool>> IsPersonYoung()
    {
        return person => person.Age <= Age;
    }

private Expression<Func<Person, bool>>  IsPersonInShape()
    {
        return person => person.Weight <= Weight;
    } 

在控制台应用中,我创建了以下“人物”

var mark = new Person
        {
            Age = 30,
            EyeColor = EyeColor.Blue,
            Height = 69,
            Name = "Mark",
            Weight = 185
        };
var austin = new Person
            {
                Age = 70,
                EyeColor = EyeColor.Brown,
                Height = 64,
                Name = "Austin Powers",
                Weight = 135
            };
var napolean = new Person
        {
            Age = 17,
            EyeColor = EyeColor.Green,
            Height = 71,
            Name = "Napolean Dynamite",
            Weight = 125
        };

主程序会列出这些人员并称之为“人员”,只是要求用户提供年龄,眼睛颜色和体重的搜索参数。然后按如下方式调用人员列表:newList = people.Where(person => coolKidCriteria.AgeAndEyesMatch(person)).ToList();newNewList = people.Where(person => coolKidCriteria.AgeAndWeightMatch(person)).ToList();

考虑到MaxAge = 20,EyeColor = EyeColor.Blue,MaxWeight = 150的参数,我希望第一个列表为空,第二个列表只包含Napolean Dynamite ......但是我收到第一个填充的列表与Mark,以及填充了Austin Powers和Napolean Dynamite的第二个列表......我能想到的意外行为的唯一原因是两个Func的'+'运算符导致了问题。只是想知道是否有人可以解释原因。我推断出只评估了两者中的第二个函数:AgeAndEyeColor =(年龄不评估)+(仅适用于Mark的眼睛颜色匹配)和AgeAndInShape =(年龄不评估)+(Austin和Napolean .InShape = =真)

我为应用程序的歧视语气道歉......这对我来说只是一个学习的东西,我没有其他背景。

2 个答案:

答案 0 :(得分:5)

当您在两个+上使用Func<int, bool>时,您告诉C#创建一个调用您的两个原始函数Func<int, bool>的{​​{1}} && 1}}结果。相反,您告诉C#创建一个调用两个函数的multicast delegate返回最后一个结果

例如,

static Func<int, bool> Fizz = i => i % 3 == 0;
static Func<int, bool> Buzz = i => i % 5 == 0;
static Func<int, bool> FizzBuzz = Fizz + Buzz;

static void Main(string[] args)
{
    var fiveIsFizzBuzz = FizzBuzz(5); // gives true
}

如果您需要&&,则必须手动执行:

static Func<int, bool> FizzBuzz = i => Fizz(i) && Buzz(i);

如果所有内容都必须是表达式,则可以使用以下内容:

static Expression<Func<int, bool>> Fizz = i => i % 3 == 0;
static Expression<Func<int, bool>> Buzz = i => i % 5 == 0;
static Expression<Func<int, bool>> FizzBuzz = Expression.Lambda<Func<int, bool>>(
    Expression.AndAlso(Fizz.Body, Expression.Invoke(Buzz, Fizz.Parameters[0])),
    Fizz.Parameters[0]);

答案 1 :(得分:1)

我之前发现了这个......我会一直在寻找参考资料:

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters); return Expression.Lambda<Func<T, bool>> (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); }

然后我像这样使用它:

public Func<Person, bool> AgeAndEyesMatch { get { return IsPersonYoung().And(PersonHasRightEyeColor()).Compile(); } }

在控制台中:

var theList = people.Where(person => coolKidCriteria.AgeAndEyesMatch(person)).ToList();

所以这个工作......但是我再次赞扬那些提出延伸方法的人...而且......不是我......但我已经发现它可以工作了。