2

我正在尝试编写一个可以链接的通用方法参数验证功能(流利的接口)以附加越来越多的验证/检查,例如:

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()方法来返回可以被链式扩展方法使用的东西。

问题

  1. 我想避免多次Compile()调用,所以基本上我的Create()方法应该返回Func<T>,而拒绝方法应该是Func<T>.
  2. 如果我Create()确实返回Func<T>,我没有机会读取应该提供给各种异常的参数名称(使用MemberExpression)。
  3. 如果我返回Expression<Func<T>>,我将不得不调用Compile()每个Reject扩展方法。

问题

  1. 是否有已经进行这种链接的 C# 库?
  2. 如果没有,你建议如何做到这一点?来自网络的任何示例都将受到热烈欢迎。

附加说明

我应该指出,复杂/长验证调用代码在这里不是一个选项,因为我当前的验证是这样完成的:

if (user == null)
{
    throw new ArgumentNullException("user");
}

或者

if (string.IsNullOrEmpty(description))
{
    throw new ArgumentNullException("description");
}

它有两个主要缺点:

  1. 我一遍又一遍地重复相同的代码行
  2. 它使用魔术字符串

因此,验证应按照上述所需场景中的每次检查使用一个衬垫来完成。

4

2 回答 2

0

罗伯特,

我有一个图书馆可以解决这个问题。它被称为Bytes2you.Validation ( Project )。它是快速、可扩展、直观且易于使用的 C# 库,为参数验证提供流畅的 API。

它完全专注于您要解决的问题,但使用表达式。之所以如此,是因为它们比仅传递参数名称要慢得多。对于这样的库,它被设计为在任何地方使用,性能是最关键的特性之一。

例如:

Guard.WhenArgument(stringArgument,"stringArgument").IsNullOrEmpty().IsEqual("xxx").Throw();  
// Which means - when stringArgument is null or empty OR is equal to "xxx" we will throw exception. If it is null, we will throw ArgumentNullException. If it is equal to "xxx", we will throw ArgumentException.
于 2015-04-18T18:39:29.240 回答
0

有一种简单的方法可以实现这样一个流畅的界面。您的“ParameterHelper.Create”方法应该返回某个类的实例(该类在Requirements下面命名)。此实例应包含传递给的表达式Create。这个类也应该有Require... 实例方法来验证表达式和返回thisRequirementsclass 可以是私有类里面ParameterHelper。我还要为这个需求链介绍一个接口(这个接口在IRequirements下面命名。示例:

public static class ParameterHelper
{
    public static IRequirements Create<T>(Expression<Func<T>> expression)
    {
        return new Requirements{ Expression = expression };
    }

    private class Requirements<T> : IRequirements
    {
        public readonly Expression<Func<T>> Expression { get; set; }

        public IRequirements RejectNull()
        {
            if (Expression .Compile()().Equals(default(T)))
            {
                MemberExpression param = (MemberExpression)Expression.Body;
                throw new ArgumentNullException(param.Member.Name);
            }
            return this;
        }

        // other Require... methods implemented in the same way
    }
}

public interface IRequirements
{
    IRequirements RejectNull();
}

这种方法将允许您实现您的luxurious解决方案 - 您只需向Reject...方法添加相应的参数。此外,您可能需要使IRequirements接口通用。

于 2011-03-07T11:50:30.323 回答