2016-02-09 4 views
4

Я создал простой класс ArgumentValidator, чтобы упростить предварительные условия аргумента в любом заданном методе. Большинство из них null или Bounds проверки, и это становится довольно утомительным после несколькихПолучение имени вызываемого абонента метода расширения

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); 
} 

в идеале я хотел бы, чтобы избавиться от nameof(flob) в Validate вызова и в конечном итоге избавиться от Validate alltoge Ther; единственная цель Validate состоит в том, чтобы не пропускать nameof(...) при каждой проверке цепи.

Есть ли способ получить имя flob внутри метода Validate()?

ответ

3

Выполнение этого с использованием метода расширения не так просто. Это проще статический метод, который принимает выражение 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(); 
+0

Спасибо, это очень интересно. Является ли что-то подобное способом расширения даже возможным? Я могу жить с обычным статическим методом «Validate», но мне любопытно, почему это метод расширения делает все сложнее. – InBetween

+0

Ну, ваша собственность должна быть выражением тогда ... На мой взгляд, это не работает. –

Смежные вопросы