【发布时间】:2014-10-16 00:00:21
【问题描述】:
我正在尝试将数字操作数表达式的字符串值(“GreaterThan”、“Equals”等)传递给参数。我已经创建了下面的代码,但它“笨拙”。我不喜欢 if 块,我认为有一种方法可以使用自定义 LINQ 比较谓词来做到这一点。我尝试关注 this post 中的回复,但似乎无法关注。关于如何清理我的方法的任何想法?
这里的代码显示了我想如何将字符串值“GreaterThan”传递给函数
var myValues = new Dictionary<string, int> {{"Foo", 1}, {"Bar", 6}};
var failed = DoAnyValuesFail(myValues, "GreaterThan", 4);
这是我写的“笨拙”的示例方法:
public bool DoAnyValuesFail(Dictionary<string, int> dictionary, string expression, int failureValue)
{
var failureValues = new List<KeyValuePair<string, int>>();
if (expression == "GreaterThan")
failureValues = dictionary.Where(x => x.Value > failureValue).ToList();
if (expression == "LessThan")
failureValues = dictionary.Where(x => x.Value < failureValue).ToList();
if (expression == "Equals")
failureValues = dictionary.Where(x => x.Value == failureValue).ToList();
return failureValues.Any();
}
--- 更新 - 最终版本 ---
我认为以下回复中的部分困惑在于我对函数、谓词和委托的术语没有那么快。对于那个很抱歉。无论如何,我确实想澄清一件事,那就是“GreaterThan”、“LessThan”和“Equals”的值来自配置文件,因此它们需要是在运行时调整的“Magic Strings”。
因此,根据 Matthew Haugen 和 Enigmativity 的反馈,我提出了以下我认为最适合我需要的代码。如果您认为这是错误的或需要调整,我愿意接受任何建议。
// These values actually come from a configuration file... shown here as hard coded just for illustration purposes
var failureValue = 2;
var numericQualifier = "<";
// This comes from my external data source
var myValues = new Dictionary<string, int> { { "Foo", 1 }, { "Bar", 6 } };
// This is the delegate (am I using that term correctly?) called Compare which is setup as an extension method
var failureValues = myValues.Where(x => numericQualifier.Compare()(x.Value, failureValue)).ToList();
if (failureValues.Any())
Console.WriteLine("The following values failed: {0}", string.Join(", ", failureValues));
这就是我的Compare扩展方法:
public static class MyExtensions
{
public static Func<int, int, bool> Compare(this string expression)
{
switch (expression)
{
case "GreaterThan":
case ">":
return (v, f) => v > f;
case "LessThan":
case "<":
return (v, f) => v < f;
case "Equals":
case "=":
return (v, f) => v == f;
default:
throw new ArgumentException(string.Format("The expression of '{0}' is invalid. Valid values are 'GreaterThan', 'LessThan' or 'Equals' or their respective symbols (>,<,=)", expression));
}
}
}
【问题讨论】:
-
我想弄清楚你为什么要这样做。在我看来,与其创建和调用名为“DoAnyValuesFail”的方法,实际上将其编码为例如更具可读性。 "var failed = myValues.Values.Any(v => v > 4);"
-
我还看到您使用“创建一个多余的对象”反模式对方法进行了编码。 IE。 “var failureValues = new List
>();”稍后您将在其中为变量分配一些不同的值。不要那样做。 -
@PeterDuniho - 您的最后一条评论通常是一个很好的观点,但我怀疑在这种情况下,OP 试图抓住
expression不是三个选择之一的情况。如果没有初始声明,此代码将无法工作。 -
@Enigmativity:啊,是的。你是对的,在这种特殊情况下,由于代码的编写方式,他需要默认实例。也就是说,如果“failureValues”此时仍然为空,我认为最好初始化为 null 并在最后返回 false。另一方面,它是一个短暂的空 List
,所以也许多余的对象在这里没有任何害处。第三方面,我仍然认为这是一种反模式。 :) -
@PeterDuniho - 是的,我同意 - 这是一种反模式。会导致失败。