我有一个静态类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 :(得分: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");
}
}
此外,Microsoft Research还有一个名为“Code Contracts”的类似项目。您可以在此处详细了解: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);
}
答案 1 :(得分: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");
}
我听过这种方法的一个论点是堆栈框架的顶部不是异常的来源,但我对客户读取堆栈爬行的能力更有信心。
答案 2 :(得分:1)
这与我的其他答案截然不同,所以我要创建一个新答案。另一种选择是通过AOP之类的框架使用PostSharp。这种方法的警告是AOP通常需要修改编译器以添加自定义编译步骤或与依赖注入相结合才能工作。一般来说这很好,但根据您的环境,它可以被视为一种限制。
PostSharp有一个关于这个问题的教程,让你用一些属性来装饰你的方法参数,这些属性将强制执行&#34;合同&#34;:
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