如果返回true则返回更新的简洁/惯用方式继续使用代码;如果为false,则返回或退出

时间:2017-05-16 22:03:49

标签: c#

我有一些项目 - 我们只需称呼他们itemAitemBitemCitemD - 我想验证他们每个人都使用我写过的验证方法。

验证方法的返回类型和签名如下:

public async Task<ValidationMessage> ValidateItem(MyClass item);

ValidationMessage是一个简单的类:

public class ValidationMessage
{
    public bool Success { get; set; }
    public string ErrorMessage { get; set; }
}

要验证每个项目,目前我有以下代码:

ValidationMessage result = new ValidationMessage();
result = await this.ValidateItem(itemA);
if (!result.Success)
{
    return result;
}
result = await this.ValidateItem(itemB);
if (!result.Success)
{
    return result;
}
result = await this.ValidateItem(itemC);
if (!result.Success)
{
    return result;
}
result = await this.ValidateItem(itemD);
return result;

正如您所看到的,只要其中一个项目未通过验证方法(意为result.Success == false),我就会返回,并且不会继续验证其余项目。

我认为重复分配结果和重复的if语句有点乏味/丑陋。我希望有一些现有的c#class / construct(也许LINQ可以帮助)更简洁地写这个。我编写了以下内容来展示我的想法:

ValidationMessage result = new ValidationMessage();
result = await this.ValidateItem(itemA).ContinueConditional(
            (r => r.Success) => await this.ValidateItem(itemB).ContinueConditional(
                (r => r.Success) => await this.ValidateItem(itemC).ContinueConditional(
                    (r => r.Success) => await this.ValidateItem(itemD))));
return result;

基本上,this.ValidateItem(itemA)的返回值已分配给result,然后此值会转到ContinueConditional。如果结果r具有Success == true,则继续验证itemB,依此类推。如果它不成功,则退出该代码并直接进入底部的return语句,从而返回未通过验证的项目。如果所有项目都经过验证,那么无论如何都会转到该返回语句。

我为长篇文章道歉,特别是如果c#构造已经存在并且很明显。我很感激任何帮助。

注意:为了发布此内容,我简化了我的实例。简化的一个重要部分是itemAitemBitemCitemD 不是同一类型,尽管它们被称为上面的方法签名中的MyClass。所以我不能把它们放在一个列表中并使用LINQ。这也意味着我实际上有不同的验证方法来接受我所拥有的各种项目,但我并不想在顶部解释所有这些,以防它过于复杂。重要的是,他们都返回ValidationMessage

5 个答案:

答案 0 :(得分:3)

如何在检查成功/失败时反转逻辑?

ValidationMessage result = await this.ValidateItem(itemA);
if (result.Success) result = await this.ValidateItem(itemB);
if (result.Success) result = await this.ValidateItem(itemC);
if (result.Success) result = await this.ValidateItem(itemD);
return result;

答案 1 :(得分:2)

这个怎么样?您可以根据需要将其扩展为任意数量的元素。

var  validationRules = new List<Func<Task<bool>>>(){
                        () => ValidateItem(itemA),
                        () => ValidateItem(itemB),
                        () => ValidateItem(itemC),
                        () => ValidateItem(itemD),
            };

        ValidationMessage result = new ValidationMessage();


        foreach(var validationRule in validationRules)
        {
            result = await validationRule();

            if(!result)
                return result;
        }

        return result;

答案 2 :(得分:2)

您可以使用FluentValidation创建自定义规则以循环浏览要验证的模型列表。这比其他答案的开销更大,但它是一个干净可读代码的好方法。

首先定义您的共享模型

public class YourSharedModel()
{
    List<MyClass> Models = new List<MyClass>();
}

定义验证器:

public class SharedModelValidator : AbstractValidator<YourSharedModel>
{
    public SharedModelValidator()
    {
        CustomRule(BeValid)
    }

    public bool BeValid(ValidationErrors<YourSharedModel> validationFailures, YourSharedModel sharedModel, ValidationContext<YourSharedModel> validationContext)
    {
        for (var m in sharedModel.Models)
        {
            var result = YourValidationMethod(m);
            if (!result.Success)
            {
                validationFailures.AddFailureFor(x => m, result.ErrorMessage);
                return false;
            }
        }
        return true;
    }

    private YourValidationMethod(MyClass model)
    {
        // the code you have that actually validates
    }
}

实施将类似于:

var yourSharedModel = new YourSharedModel();
yourSharedModel.Models.Add(itemA);
yourSharedModel.Models.Add(itemB);
// etc

var validator = new SharedModelValidator();
var results = validator.Validate(yourSharedModel);
if (!results.IsValid)
{
    // do something with results.Errors
}

您还可以保留所有错误并在循环后返回false,以便您在提交时一次性获取所有错误,而不是逐个获取错误,当然,这是假设来自Web应用程序的表单发布。提供更好的用户友好体验。

答案 3 :(得分:1)

您可以使用界面,然后将您的项目添加到foreach

的列表中
ValidationMessage Test()
 {
  List<IValidatable> items = new List<IValidatable>();
  MyClass1 item1 = new MyClass1();
  MyClass2 item2 = new MyClass2();

  items.Add(item1);
  items.Add(item2);

  ValidationMessage result = null;
  foreach (var i in items)
  {
    result = i.ValidateItem();
    if (!result.Success) break;
  }

  return result;
}

interface IValidatable
{
  ValidationMessage ValidateItem();
}
public class ValidationMessage
{
  public bool Success { get; set; }
  public string ErrorMessage { get; set; }
}

public class MyClass1 : IValidatable
{
  public ValidationMessage ValidateItem()
  {
    return new ValidationMessage();
  }
}

public class MyClass2 : IValidatable
{
  public ValidationMessage ValidateItem()
  {
    return new ValidationMessage();
  }
}

答案 4 :(得分:1)

另一种(也许是正统的)方法是超载&amp;&amp; ValidationMessage上的运算符:

public class ValidationMessage
{
    public bool Success { get; set; }
    public string ErrorMessage { get; set; }

    public static ValidationMessage operator &(ValidationMessage message1, ValidationMessage message2)
    {
        return message1.Success ? message2 : message1;
    }

    public static ValidationMessage operator |(ValidationMessage message1, ValidationMessage message2)
    {
        return message1.Success ? message1 : message2;
    }

    public static bool operator true(ValidationMessage message)
    {
        return message.Success;
    }

    public static bool operator false(ValidationMessage message)
    {
        return !message.Success;
    }
}

然后你可以这样做:

return (await this.ValidateItem(ItemA)) &&
       (await this.ValidateItem(ItemB)) &&
       (await this.ValidateItem(ItemC)) &&
       (await this.ValidateItem(ItemD));