使用字符串值为数字操作数创建自定义谓词 [英] Creating a Custom Predicate using a String Value for the Numeric Operand

查看:90
本文介绍了使用字符串值为数字操作数创建自定义谓词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将数字操作数表达式的字符串值("GreaterThan","Equals"等)传递给参数.我创建了下面的代码,该代码可以工作,但它笨拙".我不喜欢if块,而且我认为有一种方法可以使用自定义LINQ比较谓词.我试着按照

I am trying to pass in a string value ("GreaterThan", "Equals", etc.) for a numeric operand expression to a parameter. I have created the code below which works, but it's "clunky". I don't like the if blocks and I think there's a way to do this with a custom LINQ comparison predicate. I tried to follow the reply posted in this post, but I can't seem to follow it. Any ideas on how to clean up my method?

这里的代码显示了我想如何将字符串"GreaterThan"传递给函数

Here's code showing how I want to pass a string value of "GreaterThan" to a function

    var myValues = new Dictionary<string, int> {{"Foo", 1}, {"Bar", 6}};
    var failed = DoAnyValuesFail(myValues, "GreaterThan", 4);

这是我写的笨拙"的示例方法:

Here's the sample method that I wrote that's "clunky":

    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"的值来自配置文件,因此它们必须是在运行时进行调整的魔术字符串".

I think part of the confusion in the responses below is that I'm not that up to speed on my terminology of fuctions, predicates and delegates. Sorry about that. Regardless, I did want to clarify one thing and that is that the values of "GreaterThan", "LessThan" and "Equals" come from a configuration file, so they need to be "Magic Strings" that adjust at run time.

因此,基于Matthew Haugen和Enigmativity的反馈,我提出了以下代码,我认为这些代码最适合我的需求.如果您认为这是错误的或需要调整的,我欢迎您提出任何建议.

Therefore, based on the feedback from Matthew Haugen and Enigmativity, I have come up with the following code that I think works best for my needs. I'm open to any suggestions if you think it's wrong or needs adjusted.

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

推荐答案

鉴于您需要将表达式与字符串进行匹配,我倾向于这样做:

Given your requirement to match the expression against a string I would be inclined to do this:

private Dictionary<string, Func<int, int, bool>> _predicates =
    new Dictionary<string, Func<int, int, bool>>
    {
        { "GreaterThan", (v, f) => v > f },
        { "LessThan", (v, f) => v < f },
        { "Equals", (v, f) => v == f },
    };

public bool DoAnyValuesFail(
    Dictionary<string, int> dictionary,
    string expression,
    int failureValue)
{
    return _predicates.ContainsKey(expression)
        ? dictionary.Any(kvp => _predicates[expression](kvp.Value, failureValue))
        : false;
}

但是,正如其他人所说,我认为这是一个更好的选择:

However, as others have said I think this is a better option:

public bool DoAnyValuesFail(
    Dictionary<string, int> dictionary,
    Func<int, bool> predicate)
{
    return dictionary.Any(kvp => predicate(kvp.Value));
}

然后像这样简单地调用它:

And then simply call it like so:

var failed = DoAnyValuesFail(myValues, x => x > 4);

但是,将它变得更加简单仅一步之遥:

But then you are only one step away from making it even simpler:

var failed = myValues.Any(x => x.Value > 4);

不需要DoAnyValuesFail方法-意味着代码更简单,潜在的错误更少,并且没有魔术"字符串.

No DoAnyValuesFail method required - meaning simpler code, less potential bugs, and no "magic" strings.

此代码比您的原始代码更清晰,更简洁.

This code is much clearer and actually more terse than your original line.

这篇关于使用字符串值为数字操作数创建自定义谓词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆