我正在尝试编写一个通用方法参数验证功能,可以链接(流畅的接口)来附加越来越多的验证/检查,例如:
public void SomeMethod(User user, string description)
{
ParameterHelper
.Create(() => user)
.RejectNull();
ParameterHelper
.Create(() => description)
.RejectNull()
.RejectEmptyString();
// now this would be luxurious
ParameterHelper
.Create(() => new { user = user, desc = description })
.RejectNull(o => o.user)
.RejectNull(o => o.desc)
.RejectEmptyString(o => o.desc);
}
我想使用这个辅助类来测试方法参数的某些值,然后再使用它们(大多数将测试 null
的时间)。
当前事态
我首先开始编写没有Create()
方法的静态帮助器类,例如:
public static class ParameterHelper
{
public static void RejectNull(Expression<Func<T>> expr)
{
if (expr.Compile()().Equals(default(T)))
{
MemberExpression param = (MemberExpression)expr.Body;
throw new ArgumentNullException(param.Member.Name);
}
}
}
但这不允许链接。这就是为什么我创建了 Create()
方法,该方法将返回可由链式扩展方法使用的内容。
我想避免多次 Compile()
调用的问题
- ,所以基本上我的
Create()
方法应该返回 Func
并拒绝方法应该是Func
的扩展方法。
- 如果我的
Create()
确实返回 Func
我没有机会读取应提供给各种异常的参数名称(使用 MemberExpression< /代码>)。
- 如果我返回
Expression>
,我将必须在每个 Reject
扩展方法中调用 Compile()
。
问题
- 是否有一个 C# 库已经可以进行这种链接?
- 如果没有,您建议如何完成此操作?热烈欢迎来自网络的任何示例。
附加说明
我应该指出,复杂/长的验证调用代码在这里不是一个选项,因为我当前的验证是这样完成的:
if (user == null)
{
throw new ArgumentNullException("user");
}
或
if (string.IsNullOrEmpty(description))
{
throw new ArgumentNullException("description");
}
它有两个主要缺点:
- 我一遍又一遍地重复相同的代码行,
- 它使用魔术字符串
所以验证在所需的情况下,应按照上述方式在每次检查时使用一个衬垫。
I'm trying to write a generic method parameter validation functionality that can be chained (fluent interface) to attach more and more validations/checks like:
public void SomeMethod(User user, string description)
{
ParameterHelper
.Create(() => user)
.RejectNull();
ParameterHelper
.Create(() => description)
.RejectNull()
.RejectEmptyString();
// now this would be luxurious
ParameterHelper
.Create(() => new { user = user, desc = description })
.RejectNull(o => o.user)
.RejectNull(o => o.desc)
.RejectEmptyString(o => o.desc);
}
I would like to use this helper class to test method parameters for certain values before using them (most of the time null
will be tested).
Current state of affairs
I first started writing static helper class without the Create()
method like:
public static class ParameterHelper
{
public static void RejectNull(Expression<Func<T>> expr)
{
if (expr.Compile()().Equals(default(T)))
{
MemberExpression param = (MemberExpression)expr.Body;
throw new ArgumentNullException(param.Member.Name);
}
}
}
But this doesn't allow chaining. That's why I created the Create()
method that would return something that can be used by chained extension methods.
The problem
- I would like to avoid multiple
Compile()
calls, so basically my Create()
method should return Func<T>
and reject methods should be extension methods of Func<T>
.
- If my
Create()
does return Func<T>
I don't get the chance to read parameter names that should be supplied to various exceptions (using MemberExpression
).
- If I return
Expression<Func<T>>
instead I will have to call Compile()
in each Reject
extension method.
Questions
- Is there a C# library that already does this kind of chaining?
- If not, what do you suggest how this should be done? Any examples from the web would be warmly welcome.
Additional note
I should point out that complex/long validation invocation code is not an option here, because my current validation is done like:
if (user == null)
{
throw new ArgumentNullException("user");
}
or
if (string.IsNullOrEmpty(description))
{
throw new ArgumentNullException("description");
}
Which has two major drawbacks:
- I repeat the same lines of code over and over
- it uses magic strings
So validation should be done with a one liner per check as described above in the desired scenario.
发布评论
评论(2)
有一种简单的方法可以实现这样一个流畅的界面。您的“ParameterHelper.Create”方法应返回某个类的实例(该类在下面名为
Requirements
)。该实例应保存传递给Create
的表达式。此外,此类应该具有Require...
instance 方法,该方法将验证表达式并返回this
。Requirements
类可以是ParameterHelper
内的私有类。我还将介绍此需求链的一个接口(该接口在下面被命名为IRequirements
。示例:这种方法将允许您实现您的
豪华
解决方案 - 您只需添加一个此外,您可能需要使IRequirements
接口通用。There is a simple way to implement such a fluent interface. Your 'ParameterHelper.Create' method should return an instance of some class (this class is named
Requirements
below). This instance should hold the expression which was passed toCreate
. Also this class should haveRequire...
instance methods which will validate expression and returnthis
.Requirements
class can be a private class insideParameterHelper
. I would also introduce an interface for this requirements chain (this interface is namedIRequirements
below. Sample:This approach will allow you implementing your
luxurious
solution - you just need to add a corresponding parameters toReject...
methods. Also you will probably need to makeIRequirements
interface generic.罗伯特,
我有一个库可以解决这个问题。它称为 Bytes2you.Validation (Bytes2you.Validation) com/veskokolev/Bytes2you.Validation" rel="nofollow">项目)。它是快速、可扩展、直观且易于使用的 C# 库,为参数验证提供流畅的 API。
它完全关注您想要解决的问题,但不使用表达式。之所以如此,是因为它们比仅传递参数名称要慢得多。对于这样的库,其设计目的是在任何地方使用,性能是最关键的功能之一。
例如:
Robert,
I have a library that solves this problem. It is called Bytes2you.Validation (Project). It is fast, extensible, intuitive and easy-to-use C# library providing fluent APIs for argument validation.
It focuses exactly on the problem that you want to solve, but does not use expressions. This is so, because they are a lot slower than just passing the argument name. For a library like that, that is designed to be used everywhere the performance is one of the most critical features.
For example: