c# - 规范模式异步

标签 c# design-patterns async-await domain-driven-design specification-pattern

我正在尝试申请 Specification pattern到我的验证逻辑。但是我在异步验证方面遇到了一些问题。

假设我有一个实体 AddRequest (有 2 个字符串属性 FileName 和 Content)需要验证。

我需要创建 3 个验证器:

  1. 验证文件名是否不包含无效字符

  2. 验证内容是否正确

  3. 异步验证数据库中是否存在具有 FileName 的文件。在这种情况下,我应该有类似 Task<bool> IsSatisfiedByAsync 的东西

但是我怎样才能同时实现 IsSatisfiedByIsSatisfiedByAsync ?我应该创建 2 个接口(interface)吗 ISpecificationIAsyncSpecification或者我可以一次性完成吗?

我的版本ISpecification (我只需要And)

    public interface ISpecification
    {
        bool IsSatisfiedBy(object candidate);
        ISpecification And(ISpecification other);
    }

和规范

public class AndSpecification : CompositeSpecification 
{
    private ISpecification leftCondition;
    private ISpecification rightCondition;

    public AndSpecification(ISpecification left, ISpecification right) 
    {
        leftCondition = left;
        rightCondition = right;
    }

    public override bool IsSatisfiedBy(object o) 
    {
        return leftCondition.IsSatisfiedBy(o) && rightCondition.IsSatisfiedBy(o);
    }
}

要验证文件是否存在,我应该使用:

 await _fileStorage.FileExistsAsync(addRequest.FileName);

我怎么写IsSatisfiedBy为了检查我是否真的需要执行异步操作?

例如这里我的文件名验证器 (1)

public class FileNameSpecification : CompositeSpecification 
{
    private static readonly char[] _invalidEndingCharacters = { '.', '/' };
    
    public override bool IsSatisfiedBy(object o) 
    {
        var request = (AddRequest)o;
        if (string.IsNullOrEmpty(request.FileName))
        {
            return false;
        }
        if (request.FileName.Length > 1024)
        {
            return false;
        }
        if (request.FileName.Contains('\\') || _invalidEndingCharacters.Contains(request.FileName.Last()))
        {
            return false;
        }

        return true
    }
}

我需要创建 FileExistsSpecification 并像这样使用:

var validations = new FileNameSpecification().And(new FileExistsSpecification());
if(validations.IsSatisfiedBy(addRequest)) 
{ ... }

但是我怎样才能创建FileExistsSpecification如果我需要异步?

最佳答案

But how can I implement both IsSatisfiedBy and IsSatisfiedByAsync? Should I create 2 interfaces like ISpecification and IAsyncSpecification or can I do that in one?

您可以同时定义同步和异步接口(interface),但任何通用复合实现都必须只实现异步版本。

asynchronous methods on interfaces mean "this might be asynchronous"而同步方法意味着“这个必须是同步的”,我会选择一个仅异步的接口(interface),例如:

public interface ISpecification
{
  Task<bool> IsSatisfiedByAsync(object candidate);
}

如果您的许多规范是同步的,您可以用一个基类来帮忙:

public abstract class SynchronousSpecificationBase : ISpecification
{
  public virtual Task<bool> IsSatisfiedByAsync(object candidate)
  {
    return Task.FromResult(IsSatisfiedBy(candidate));
  }
  protected abstract bool IsSatisfiedBy(object candidate);
}

复合 Material 将是:

public class AndSpecification : ISpecification 
{
  ...

  public async Task<bool> IsSatisfiedByAsync(object o) 
  {
    return await leftCondition.IsSatisfiedByAsync(o) && await rightCondition.IsSatisfiedByAsync(o);
  }
}

public static class SpecificationExtensions
{
  public static ISpecification And(ISpeicification @this, ISpecification other) =>
      new AndSpecification(@this, other);
}

和个别规范本身:

public class FileExistsSpecification : ISpecification
{
  public async Task<bool> IsSatisfiedByAsync(object o)
  {
    return await _fileStorage.FileExistsAsync(addRequest.FileName);
  }
}

public class FileNameSpecification : SynchronousSpecification 
{
  private static readonly char[] _invalidEndingCharacters = { '.', '/' };

  public override bool IsSatisfiedBy(object o) 
  {
    var request = (AddRequest)o;
    if (string.IsNullOrEmpty(request.FileName))
      return false;
    if (request.FileName.Length > 1024)
      return false;
    if (request.FileName.Contains('\\') || _invalidEndingCharacters.Contains(request.FileName.Last()))
      return false;
    return true;
  }
}

用法:

var validations = new FileNameSpecification().And(new FileExistsSpecification());
if (await validations.IsSatisfiedByAsync(addRequest))
{ ... }

关于c# - 规范模式异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45676819/

相关文章:

c# - 如何让AsyncLocal流向 sibling ?

c# - 我需要在我的类构造函数中设置初始值吗?

c# - VS 2015 实习生 Android 模拟器无法启动 (vmWare 10)

java - 为应用程序实现一个通用的观察者模式/监听器

c# - 为什么在控制台应用程序中使用 async/await 时需要 AsyncContext?

javascript - Async/Await - 如何在递归 Ajax 函数中实现 Javascript Async-Await?

c# - 如何获取进程的主窗口(而不是窗口句柄)?

java - 仅使用一个循环打印图案

css - 串联类(class)是好的做法吗?

javascript - 如何解决 Firebase 函数中的嵌套异步数据库调用