2014-12-02 99 views
1

检查参数的方法我有一个静态类ArgumentHelper其可以检查,例如:ArgumentHelper.NotNull(instance, "instance")。但它为一些标准内置.NET框架类,如果我实现我自己的班,我不能在ArgumentHelper就把检查,因为这个类将是太大。 所以我在想,我找到了解决办法:我会做一个嵌套的静态类在每一个新的做定制类:一组用于嵌套静态类

public class MyClass 
{ 
    private int x; 

    public MyClass (int x) 
    { 
     if (x < 0) throw new ArgumentOutOfRangeException (...); 

     this.x = x; 
    } 

    public static class Arg 
    { 
     public static void NotZero (MyClass mc) 
     { 
      if (mc.x == 0) throw .... 
     } 
    } 
} 

所以现在:

public void myMethod (MyClass mc) 
{ 
    MyClass.Arg.NotZero (mc); // will throw excweption if x == 0 

    do some stuff 
} 

这是个好主意,或你有不同的方法?

+0

“如果我实现我自己的班,我不能放在一个检查rgumentHelper,因为这个班级会太大“ - 为什么?如果你正在检查常见的东西(无效,参数超出范围),那么我希望你会发现许多类中都使用相同的条件 - 为什么你要重复它们? – 2014-12-02 15:08:02

+1

我假设你想实现['Debug.Assert'](http://msdn.microsoft.com/en-us/library/system.diagnostics.debug.assert%28v=vs.110%29.aspx) :http://stackoverflow.com/questions/129120/when-should-i-use-debug-assert – 2014-12-02 15:09:51

+0

在我的自定义类我不检查常见的东西。就像我在示例中所示,我正在检查x是== 0.也许它不是很好,但对于更复杂的场景,如果我想检查3个变量,例如Point不能是0,0,0,它会产生3行代码。我想只是Point.Arg.NotZero(p) – zgnilec 2014-12-02 15:10:28

回答

1

有许多方法可以做到这一点,但我会说这种方式过于复杂。您可以创建一个具有检查不同参数逻辑的静态类,而不是在整个地方创建类。例如:

//Common methods for validating method parameters 
public static class Ensure 
{ 
     public static void NotNull(object o, string paramName) 
     { 
      if (null == o) 
       throw new ArgumentNullException(paramName); 
     } 

     public static void NotZero(Point p, string paramName){ /*logic*/ } 

     public static void GreaterThanZero(int i, string paramName) 
     { 
      if (i <= 0) 
       throw new ArgumentException("Must be greater than zero", paramName); 

     } 
} 

然后在您的类:

public class MyCustomClass 
{ 
     public void SomeMethod(object o, int i, Point p) 
     { 
      //Guards 
      Ensure.NotNull(o, "o"); 
      Ensure.GreaterThanZero(i, "i"); 
      Ensure.NotZero(p, "p"); 
     } 
} 

此外,微软研究院也有一个类似的项目名为 “代码契约”。你可以阅读更多关于它在这里:http://visualstudiomagazine.com/articles/2010/06/23/code-contracts.aspx

更新

在努力减少线路的数量,你可以做这样的事情:

public static class Ensure 
{ 
    public static void NotNull(params object[] objects) 
    { 
     if (objects.Any(x => null == x) 
      throw new ArgumentNullException(); 
    } 
} 

然后在你的方法:

public void example(object o, int i, Point p) 
{ 
    Ensure.NotNull(o, i, p); 
} 
+0

我有这样的实现。但是就像你看到的,在SomeMethod中你已经确保了3x的对象o。所以如果你有50个这样的方法,你需要额外增加150条线。所以我做像Eureure.CHeckStateOfCustomClass方法。但在此之后,确保我的成长。但即使这不是问题。问题是当我需要使用来自不同程序集的自定义类时。确保不知道这个组件,并且不能引用它。 – zgnilec 2014-12-02 17:02:25

+0

您可以将Ensure类放入单独的实用程序集合中,该实用程序集合没有任何依赖关系,因此可以被所有项目程序集引用。由于有很多确保类的行,我会发布一个小的更新,使它更好一点。另一种选择是使用类似PostSharp的NotNull属性。 – 2014-12-02 19:26:03

1

我更喜欢使用更好的命名和这个直通接口。

例如,你可以有这个类:

public static class ThrowOn 
{ 
    public static T Null<T>(T val, string name) where T : object 
    { 
     if (val == null) throw new ArgumentNullException(name); 
     return val; 
    } 
} 

,并以这种方式使用它:

private MyObject _mine; 

public SomeConstructor(MyObject mine) 
{ 
    _mine = ThrowOn.Null(mine, "mine"); 
} 

这使得它非常清楚,一个异常将被抛出。我使用泛型来确保它的类型很强,并且不能将测试结果分配给错误的类型。

我喜欢这个,因为它让你的构造漂亮整洁,走出因素代码,它不正是它说,在包装盒上。

您也可以,如果你喜欢,它读取的方式命名类ThrowIf

这也可以同样的扩展方法来实现:

public static class Extensions 
{ 
    public static T ThrowOnNull<T>(this T val, string name) where T : object 
    { 
     if (val == null) throw new ArgumentNullException(name); 
     return val; 
    } 
} 

,在使用中会是这样的:

private MyObject _mine; 

public SomeConstructor(MyObject mine) 
{ 
    _mine = mine.ThrowOnNull("mine"); 
} 

有一种说法我听到反对这种做法是顶堆栈框架不是异常的来源,但我对客户读取堆栈抓取的能力更有信心。

1

这与我的其他答案截然不同,所以我正在创建一个新的答案。另一个选择是通过像PostSharp这样的框架使用AOP。这种方法的缺陷是AOP通常需要修改编译器来添加自定义编译步骤或者与依赖注入耦合才能工作。通常这很好,但根据您的环境,它可以被视为限制。

PostSharp对这个非常的问题,它可以让你将执行“合同”属性装饰方法参数教程:

public void Foo([NotNull] string bar) {} 

PostSharp将改写这(后编译时间)

public void Foo(string bar) 
{ 
    if (null == bar) 
     throw new ArgumentNullExpcetion(bar, "bar"); 
} 

你可以阅读更多关于如何工作和这里的支持是什么:Validating parameters, fields and properties with PostSharp 3