【问题标题】:Use Func<T,bool>[] as a parameter list and check the result for each function使用 Func<T,bool>[] 作为参数列表并检查每个函数的结果
【发布时间】:2015-10-13 19:02:44
【问题描述】:

更新: 我正在尝试编写一种方法来完成某些工作,并且在它实际完成这些工作之前,它需要经过一些验证。这些验证因它要执行的工作而异。

经过一番思考,我仍然想使用相同的模式,并稍作改动。 现在,我想让以下代码工作:

SomeClass:

        public SomeResponse DoSomething<T>(params Func<T, bool>[] validations)
        {
            if(validations.All(v=>v(T))
            {
                some logic..
            }
            return SomeResponse;
        }

用法:

       private Func<SomeRequest, bool> ValidateName = r =>
        {return !string.IsNullOrWhiteSpace(r.Name);};
       private Func<SomeRequest, bool> ValidatePhone = r =>
        {return !string.IsNullOrWhiteSpace(r.Phone);};

       var someResponse = SomeClass.DoSomething<SomeRequest>(ValidateName,ValidatePhone);

再一次,代码目前不起作用,因为它给了我错误

if(validations.All(v=>v(T))

基本上Type参数在这里无效,我找不到将实际SomeRequest对象传递给Func的方法。

我应该如何编写代码循环遍历函数列表返回的所有结果并确保它们返回true,以及保持Type参数的灵活性?

答案:

找到了一种方法,希望对您有所帮助:

只需将方法定义修改为:

某类:

    public SomeResponse DoSomething<T>(T request, params Func<T, bool>[] validations)
    {
        if(validations.All(v=>v(request))
        {
            some logic..
        }
        return SomeResponse;
    }

然后像这样使用它:

var someResponse = SomeClass.DoSomething<SomeRequest>(someRequest, ValidateName,ValidatePhone);

如果有其他解决方案,请告诉我。

【问题讨论】:

  • 您不能将Func&lt;NameRequest, bool&gt;Func&lt;PhoneRequest, bool&gt; 转换为Func&lt;Request, bool&gt;Func&lt;in T, out TResult&gt; 第一个类型参数逆变。

标签: c# parameter-passing func type-parameter


【解决方案1】:

你快到了!

首先注意Validations 是一个Func&lt;Request, bool&gt; 的数组——也就是说,数组中的每一项都是一个函数,它以Request 作为参数并返回一个bool .

因此,为了从Func 中取出bool,您需要将其应用于Request 对象。在 C# 中,将 Func 应用于参数看起来就像调用方法一样。因此,您的 LINQ 表达式将如下所示:

validations.All(f => f(request))

当且仅当validations 中的所有函数都返回true(应用于request 时)时,这将返回true

所以您的完整 if 块将如下所示:

// I'm just guessing what the code to make a Request object will look like
Request request = resource.GetRequest();

if (!validations.All(f => f(request)))
{
    throw new Exception("Not all of the validations checked out");
}

您没有提供足够的上下文让我告诉您从哪里获取 Request 对象,但我相信您可以弄清楚。

【讨论】:

  • 您好,感谢您的回复。我对我的问题进行了一些编辑,以使其更具体。问题是在调用方法时传递了请求对象,就像第一个函数传入了 NameRequest 一样。它们都是 Request 的子类型,但我仍然对我可以在 if (!validations.All 中使用什么对象感到困惑(f => f(请求)))。能否请您详细解释一下?
  • 我看到了问题 - 您想将 Func&lt;NameRequest, bool&gt;Func&lt;PhoneRequest, bool&gt; 传递给 Func&lt;Request, bool&gt; 类型的参数。不幸的是,没有办法做到这一点,因为Func 在它的第一个参数中是逆变的。 Func&lt;NameRequest, bool&gt;不是Func&lt;Request, bool&gt; 的子类型。 (事实上​​反之亦然。)这对我来说意味着你需要重新考虑你的设计。 (续)
  • 您到底想达到什么目的?给定一个特定类型的Request,我们是否需要所有列表中的验证器通过?但是当我尝试使用NameRequest 但列表包含PhoneRequests 的验证器时会发生什么?对我来说更有意义的是,您真正想要为您所拥有的Request 的具体类型使用一个正确的验证器。为此,您需要在 Request (request.IsValid()) 上使用虚拟方法,或者如果您想将验证代码与需要使用 the Visitor pattern 的请求分开。
  • 非常感谢!你确实照亮了我的道路——访客模式!我怎么会忘记!我想我需要休息一下:p
【解决方案2】:

假设我正确理解这些类型,我认为这样的事情应该可行:

if (Validations.All(v => v(resource)))

【讨论】:

    【解决方案3】:

    你不需要在这里使用params,一个简单的数组就可以了。您可以通过数组传递任意数量的Func 对象。

    public void DoSomething(Resource resource, Func<Request, bool>[] Validations)
    

    无论如何,您可以轻松地使用 LINQ 的 All 方法来检查数组的所有元素是否满足谓词。

    if (Validations.All(v => v(resource)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多