【问题标题】:Getting the callee's name of an extension method获取扩展方法的被调用者名称
【发布时间】:2016-02-09 09:33:39
【问题描述】:

我建立了一个简单的ArgumentValidator 类来简化任何给定方法中的参数前提条件。他们中的大多数是null 或边界检查,经过几次之后就会变得非常乏味

if (arg == null ) throw new ArgumentNullException(nameof(arg));

所以我想出了以下设置:

public static class ArgumentValidator
{
    public interface IArgument<T>
    {
        string ParamName { get; }
        T Value { get; }
    }

    private class Argument<T>: IArgument<T>
    {
        public Argument(T argument, string paramName)
        {
            ParamName = paramName;
            Value = argument;
        }

        public string ParamName { get; }
        public T Value { get; }
    }

    public static IArgument<T> Validate<T>(this T argument, string paramName = null)
    {
        return new Argument<T>(argument, paramName ?? string.Empty);
    }

    public static IArgument<T> IsNotNull<T>(this IArgument<T> o)
    {
        if (ReferenceEquals(o.Value, null))
            throw new ArgumentNullException(o.ParamName);

        return o;
    }

    public static IArgument<T> IsSmallerThan<T, Q>(this IArgument<T> o, Q upperBound) where T : IComparable<Q> { ... }

    //etc.
}

我可以通过以下方式使用它:

public Bar Foo(object flob)
{
     flob.Validate(nameof(flob)).IsNotNull().IsSmallerThan(flob.MaxValue);
}

理想情况下,我希望在 Validate 通话中摆脱 nameof(flob) 并最终完全摆脱 ValidateValidate 的唯一目的是避免每次检查都必须通过 nameof(...)

有没有办法在Validate() 方法中获取名称flob

【问题讨论】:

    标签: c#


    【解决方案1】:

    使用扩展方法做到这一点并不容易。使用采用 LINQ 表达式(派生自 devdigital's answer here)的静态方法会更容易:

    public static T Validate<T>(this Expression<Func<T>> argument)
    {
        var lambda = (LambdaExpression)argument;
    
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = (UnaryExpression)lambda.Body;
            memberExpression = (MemberExpression)unaryExpression.Operand;
        }
        else
        {
            memberExpression = (MemberExpression)lambda.Body;
        }
    
        string name = memberExpression.Member.Name;
    
        Delegate d = lambda.Compile();
    
        return (T)d.DynamicInvoke();
    }
    

    里面的name是你放在方法里的属性名:

    MyMethods.Validate(() => o);
    

    由于Validate 返回T,您可以进一步使用它。这可能不如您希望的那样执行,但这是唯一可行的选择。

    也可以将其设为扩展方法,您必须自己手动创建表达式:

    Expression<Func<object>> f = () => o; // replace 'object' with your own type
    
    f.Validate();
    

    【讨论】:

    • 谢谢,这很有趣。做类似的事情是否可能是一种扩展方法?我可以接受Validate 一个普通的静态方法,但我很好奇为什么它是一个扩展方法会让事情变得更难。
    • 嗯,那么你的属性必须是一个表达式......在我看来这并不真正有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-19
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    相关资源
    最近更新 更多