所以这是我在使用表达式和函数时观察到的奇怪行为。
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 = =真)
我为应用程序的歧视语气道歉......这对我来说只是一个学习的东西,我没有其他背景。
答案 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();
所以这个工作......但是我再次赞扬那些提出延伸方法的人...而且......不是我......但我已经发现它可以工作了。