C# 如果返回true,则继续使用代码;如果返回false,则退出代码,这是一种更简洁/惯用的方法

C# 如果返回true,则继续使用代码;如果返回false,则退出代码,这是一种更简洁/惯用的方法,c#,C#,我有几个项目——让我们称它们为itemA,itemB,itemC,和itemD——我想使用我编写的验证方法来验证它们 验证方法返回类型和签名如下: public async Task<ValidationMessage> ValidateItem(MyClass item); 为了验证每个项目,目前我有以下代码: ValidationMessage result = new ValidationMessage(); result = await this.ValidateItem(

我有几个项目——让我们称它们为
itemA
itemB
itemC
,和
itemD
——我想使用我编写的验证方法来验证它们

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

public async Task<ValidationMessage> ValidateItem(MyClass item);
为了验证每个项目,目前我有以下代码:

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#类/构造(也许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#结构已经存在并且显而易见的话。我非常感谢你在这方面的帮助


注意:为了发布本文,我简化了我的真实示例。简化的一个重要部分是
itemA
itemB
itemC
itemD
不是同一类型,尽管在上面的方法签名中将它们称为
MyClass
。所以我不能把它们放在一个列表中,然后使用LINQ。这也意味着我实际上有不同的验证方法来接受我拥有的各种项目,但我不想在顶部解释所有这些,以免使事情变得过于复杂。重要的一点是,它们都返回
ValidationMessage

那么,在检查成功/失败的过程中,如何反转逻辑呢

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;

您可以使用一个界面,然后将您的项目添加到一个列表中,您可以通过以下方式
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();
  }
}
ValidationMessage测试()
{
列表项=新列表();
MyClass1 item1=新的MyClass1();
MyClass2 item2=新的MyClass2();
增加(第1项);
增加(第2项);
ValidationMessage结果=null;
foreach(项目中的var i)
{
结果=i.ValidateItem();
如果(!result.Success)中断;
}
返回结果;
}
接口表
{
ValidationMessage ValidateItem();
}
公共类验证消息
{
公共bool成功{get;set;}
公共字符串错误消息{get;set;}
}
公共类MyClass1:IValidatable
{
公共验证消息ValidateItem()
{
返回新的ValidationMessage();
}
}
公共类MyClass2:IValidatable
{
公共验证消息ValidateItem()
{
返回新的ValidationMessage();
}
}

这个怎么样?可以根据需要将其扩展到任意多个元素

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;
var validationRules=新列表(){
()=>验证项目(项目A),
()=>验证项目(项目B),
()=>ValidateItem(项目C),
()=>ValidateItem(项目D),
};
ValidationMessage结果=新建ValidationMessage();
foreach(validationRules中的var validationRule)
{
结果=等待验证规则();
如果(!结果)
返回结果;
}
返回结果;
您可以使用创建一个自定义规则,在要验证的模型列表中循环。这比其他答案的开销更大,但对于干净可读的代码来说,这是一种很好的方法

首先定义您的共享模型

public class YourSharedModel()
{
    List<MyClass> Models = new List<MyClass>();
}
您还可以保留所有错误,并在循环后返回false,以便一次获取所有错误,而不是在提交时逐个获取错误,当然这是假设来自web应用程序的表单post。提供更好的用户友好体验。

另一种方法(可能是anorthodox)是在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));

我很喜欢这个。我想我是如此专注于在第一次失败后立即返回,以至于我没有意识到我仍然可以使用这种逻辑返回第一个失败的项目。非常感谢。我仍然很好奇是否有这样一个符合我逻辑的结构。我不知道。不过,让我们看看是否有人有更好的想法。例如,接口方法很有趣,尽管它需要对现有类进行一些修改。如果您的项目实现一个接口,比如说
IValidatable
,那么您可以通过
foreach
运行它们。我正在考虑这样做。我并不特别喜欢为了验证而让他们实现一个接口的想法,所有的事情都认为这只是他们工作的一小部分。好吧,我不知道你在做什么。为了好玩,我还是写了一个答案:)去吧,我很欣赏人们提出的任何想法:)因为项目不是同一类型的,也许可以将匿名函数更改为
itemA.ValidateItem()
,但是,我想OP没有使用那种格式,所以没关系。@MikeH这是一个选择的问题。我想我不会把验证逻辑放在项目中。项目如何映射到适当的函数取决于如何检索这些项目。如果没有一个更大的背景,我不知道如何做到这一点,但肯定有一种方法可以很容易地绘制它。谢谢你的想法,我也很喜欢这个。它确实是在验证来自web应用程序的post请求,因此一次返回所有错误比返回一个包含第一个错误的400错误请求更方便
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
}
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));