我正在尝试申请 Specification pattern到我的验证逻辑。但是我在异步验证方面遇到了一些问题。
假设我有一个实体 AddRequest
(有 2 个字符串属性 FileName 和 Content)需要验证。
我需要创建 3 个验证器:
验证文件名是否不包含无效字符
验证内容是否正确
异步验证数据库中是否存在具有 FileName 的文件。在这种情况下,我应该有类似
Task<bool> IsSatisfiedByAsync
的东西
但是我怎样才能同时实现 IsSatisfiedBy
和 IsSatisfiedByAsync
?我应该创建 2 个接口(interface)吗 ISpecification
和 IAsyncSpecification
或者我可以一次性完成吗?
我的版本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/