You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现IValidatableObject的Ticket类调用含yield的验证方法未执行问题

迭代器方法延迟执行导致验证逻辑不触发的问题

问题背景

我们有一个实现IValidatableObject接口的Ticket类,其Validate方法根据私有属性_action执行对象验证:

  • 当_action为ETicketAction.Create时,Assignee必须为null;
  • 当_action为ETicketAction.Edit时,Assignee不可为null。

同时实现了私有方法ValidateCommonFields,用于验证ProductLineId、ProductVersion等公共字段,并在Create和Edit分支中调用。但调试发现,调用ValidateCommonFields()时从未进入方法内部,断点无响应,即使字段为空,该方法的ValidationResult也不会返回。怀疑和yield语句有关,想咨询是否该用yield return ValidateCommonFields()调用?

相关代码:

public partial class Ticket : IValidatableObject
{
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (string.IsNullOrEmpty(Summary))
        {
            yield return new ValidationResult("Summary must be set!");
        }
        
        if (_action == (int)ETicketAction.Create)
        {
            if (Assignee != null)
            {
                yield return new ValidationResult("Assignee must be null when creating a ticket!");
            }
            
            ValidateCommonFields();
        }
        else if (_action == (int)ETicketAction.Edit)
        {
            if (Assignee == null)
            {
                yield return new ValidationResult("Assignee must be set when editing a ticket!");
            }
            
            ValidateCommonFields();
        }
        else if (_action == (int)ETicketAction.Close)
        {
            // ...
        }
    }

    private IEnumerable<ValidationResult> ValidateCommonFields()
    {
        if (ProductLineId == null)
        {
            yield return new ValidationResult("Product line must be set!");
        }

        if (ProductVersion.IsNullOrEmpty())
        {
            yield return new ValidationResult($"Product version must be set!");
        }
    }
}

原因

核心问题是带yield的迭代器方法是延迟执行的。当你只调用ValidateCommonFields()而不枚举它的返回值时,方法内部的代码不会运行——迭代器方法只有在被枚举(比如foreach遍历、调用ToList()/ToArray())时才会真正执行逻辑。

解决方案

不能直接用yield return ValidateCommonFields(),因为yield return只能返回单个元素,而该方法返回的是IEnumerable<ValidationResult>。有两种常用解决方式:

方式1:遍历公共验证结果并逐个返回

修改Validate方法中调用ValidateCommonFields的逻辑,用foreach遍历其返回值并逐个yield return:

// Create分支示例
if (_action == (int)ETicketAction.Create)
{
    if (Assignee != null)
    {
        yield return new ValidationResult("Assignee must be null when creating a ticket!");
    }
    
    // 遍历公共验证结果并返回
    foreach (var result in ValidateCommonFields())
    {
        yield return result;
    }
}

// Edit分支同理
else if (_action == (int)ETicketAction.Edit)
{
    if (Assignee == null)
    {
        yield return new ValidationResult("Assignee must be set when editing a ticket!");
    }
    
    foreach (var result in ValidateCommonFields())
    {
        yield return result;
    }
}

方式2:修改公共验证方法为添加结果到列表

调整ValidateCommonFields的逻辑,让它接收一个列表并添加验证结果,避免迭代器延迟执行:

private void ValidateCommonFields(List<ValidationResult> results)
{
    if (ProductLineId == null)
    {
        results.Add(new ValidationResult("Product line must be set!"));
    }

    if (ProductVersion.IsNullOrEmpty())
    {
        results.Add(new ValidationResult($"Product version must be set!"));
    }
}

然后在Validate方法中创建列表,收集所有验证结果后返回:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var results = new List<ValidationResult>();
    
    if (string.IsNullOrEmpty(Summary))
    {
        results.Add(new ValidationResult("Summary must be set!"));
    }
    
    if (_action == (int)ETicketAction.Create)
    {
        if (Assignee != null)
        {
            results.Add(new ValidationResult("Assignee must be null when creating a ticket!"));
        }
        
        ValidateCommonFields(results);
    }
    else if (_action == (int)ETicketAction.Edit)
    {
        if (Assignee == null)
        {
            results.Add(new ValidationResult("Assignee must be set when editing a ticket!"));
        }
        
        ValidateCommonFields(results);
    }
    else if (_action == (int)ETicketAction.Close)
    {
        // ...
    }
    
    foreach (var result in results)
    {
        yield return result;
    }
}

这种方式逻辑更直观,也避免了迭代器延迟执行的坑。

内容的提问来源于stack exchange,提问作者Aleks Vujic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:05:54