可以说我有这种扩展方法:
public static bool HasFive(this IEnumerable subjects) { if(subjects == null) throw new ArgumentNullException("subjects"); return subjects.Count() == 5; }
你觉得这个空检查和异常抛出真的有必要吗?我的意思是,当我使用这种Count
方法时,ArgumentNullException
无论如何都会被抛出,对吧?
我可以想到我应该这样做的一个原因,但是我想听听别人对此的看法.是的,我问的理由是部分懒惰(想要尽可能少地写),但也因为我认为一堆空检查和异常抛出了一些混乱的方法,这些方法往往最终是他们真的需要.有人应该知道比将null发送到方法更好:p
无论如何,你们怎么想?
注意: Count()
是一个扩展方法,将抛出一个ArgumentNullException
,而不是一个NullReferenceException
.见Enumerable.Count
.如果你不相信我自己尝试=)
注2:在这里给出的答案之后,我被说服开始检查更多的空值.我仍然很懒,所以我开始Enforce
在Lokad共享库中使用该类.可以推荐看一下.而不是我的例子,我可以这样做:
public static bool HasFive(this IEnumerable subjects) { Enforce.Argument(() => subjects); return subjects.Count() == 5; }
Jon Skeet.. 19
是的,它会抛出一个ArgumentNullException
.我可以想到额外检查的两个原因:
如果你以后回去并在调用之前更改方法以执行某些操作subjects.Count()
并忘记在此时进行检查,则可能会在抛出异常之前产生副作用,这不太好.
目前,堆栈跟踪将显示subjects.Count()
在顶部,并且可能带有source
参数名称的消息.这可能会让HasFive
谁可以看到subjects
参数名称的调用者感到困惑.
编辑:只是为了救我不得不在其他地方再写一遍:
召唤subjects.Count()
将抛出一个ArgumentNullException
,而不是一个NullReferenceException
.Count()
这是另一种扩展方法,假设System.Linq.Enumerable
正在使用实现,那就是记录(正确)抛出一个ArgumentNullException
.如果你不相信我,试试吧.
编辑:让这更容易......
如果您做了很多这样的检查,您可能希望这样做更简单.我喜欢以下扩展方法:
internal static void ThrowIfNull(this T argument, string name) where T : class { if (argument == null) { throw new ArgumentNullException(name); } }
然后问题中的示例方法可以变为:
public static bool HasFive(this IEnumerable subjects) { subjects.ThrowIfNull("subjects"); return subjects.Count() == 5; }
另一种方法是编写一个检查值并返回它的版本:
internal static T NullGuard(this T argument, string name) where T : class { if (argument == null) { throw new ArgumentNullException(name); } return argument; }
然后你可以流利地调用它:
public static bool HasFive(this IEnumerable subjects) { return subjects.NullGuard("subjects").Count() == 5; }
这对于在构造函数中复制参数等也很有用:
public Person(string name, int age) { this.name = name.NullGuard("name"); this.age = age; }
(对于不重要的地方,您可能需要没有参数名称的重载.)
是的,它会抛出一个ArgumentNullException
.我可以想到额外检查的两个原因:
如果你以后回去并在调用之前更改方法以执行某些操作subjects.Count()
并忘记在此时进行检查,则可能会在抛出异常之前产生副作用,这不太好.
目前,堆栈跟踪将显示subjects.Count()
在顶部,并且可能带有source
参数名称的消息.这可能会让HasFive
谁可以看到subjects
参数名称的调用者感到困惑.
编辑:只是为了救我不得不在其他地方再写一遍:
召唤subjects.Count()
将抛出一个ArgumentNullException
,而不是一个NullReferenceException
.Count()
这是另一种扩展方法,假设System.Linq.Enumerable
正在使用实现,那就是记录(正确)抛出一个ArgumentNullException
.如果你不相信我,试试吧.
编辑:让这更容易......
如果您做了很多这样的检查,您可能希望这样做更简单.我喜欢以下扩展方法:
internal static void ThrowIfNull(this T argument, string name) where T : class { if (argument == null) { throw new ArgumentNullException(name); } }
然后问题中的示例方法可以变为:
public static bool HasFive(this IEnumerable subjects) { subjects.ThrowIfNull("subjects"); return subjects.Count() == 5; }
另一种方法是编写一个检查值并返回它的版本:
internal static T NullGuard(this T argument, string name) where T : class { if (argument == null) { throw new ArgumentNullException(name); } return argument; }
然后你可以流利地调用它:
public static bool HasFive(this IEnumerable subjects) { return subjects.NullGuard("subjects").Count() == 5; }
这对于在构造函数中复制参数等也很有用:
public Person(string name, int age) { this.name = name.NullGuard("name"); this.age = age; }
(对于不重要的地方,您可能需要没有参数名称的重载.)