.net 可枚举。任何<;T>;(这个IEnumerable<;T>;源)当然也应该处理空枚举?
Any()方法对空枚举值抛出.net 可枚举。任何<;T>;(这个IEnumerable<;T>;源)当然也应该处理空枚举?,.net,linq,.net,Linq,Any()方法对空枚举值抛出ArgumentNullException,是否有一些迂腐的基于枚举器理论的原因 我尽可能使用IEnumerable来传递数据集合,但在大多数情况下,我会使用这种代码: public class Foo { public IEnumerable<IBar> Bars { get; set; } } ////---- public static void UseAFoo(Foo foo) { //if Bars has something in
ArgumentNullException
,是否有一些迂腐的基于枚举器理论的原因
我尽可能使用IEnumerable来传递数据集合,但在大多数情况下,我会使用这种代码:
public class Foo
{
public IEnumerable<IBar> Bars { get; set; }
}
////----
public static void UseAFoo(Foo foo)
{
//if Bars has something in it, then do something:
if(foo.Bars != null && foo.Bars.Any())
{
//blah
}
}
公共类Foo
{
公共IEnumerable条{get;set;}
}
////----
公共静态无效UseAFoo(Foo-Foo)
{
//如果酒吧里有东西,那就做点什么:
if(foo.bar!=null&&foo.bar.Any())
{
//废话
}
}
或者
if((foo.bar??Enumerable.Empty()).Any())
{
//啊!
}
或修改属性声明,如下所示:
public class Foo
{
private IEnumerable<IBar> _bars;
public IEnumerable<IBar> Bars
{
get { return _bars ?? Enumerable.Empty<IBar>(); }
set { _bars = value; }
}
}
公共类Foo
{
私人可数酒吧;
公共可数酒吧
{
获取{返回_条??可枚举的.Empty();}
设置{u条=值;}
}
}
或“更高效”的方式:
get { return _bars; }
set { _bars = value ?? Enumerable.Empty<IBar>(); }
get{return\u bar;}
设置{u bar=value??可枚举的.Empty();}
在任何情况下,这都是令人讨厌的。好吧,我可以做我自己的扩展方法(我已经有了)——但是命名有点棘手,因为最好的名字已经被取了!我喜欢NotNullAndAny()
,但我不喜欢它
Any()
(以及它的委托驱动兄弟)在我看来,如果枚举值为null,则应该返回false-它不应该抛出ArgumentNullException
但是,就像我一开始说的,这里有没有我遗漏的隐藏合同?或者只是迂腐;)
更新
我有一种感觉,大家的共识是,所有linq扩展都应该抛出ArgumentNullException
,即使是Any()
——老实说,尽管我觉得Any()
仍然可以这样做,的参数不够有说服力,无法克服这样一个基本事实:如果枚举值为null,则无法令人满意地完成它的常规操作,因此必须抛出异常
因此,我将使用一个额外的扩展方法NotNullAndAny()
,来清理可能出现空值(而不是错误)的代码。在不允许空枚举的情况下,我也会抛出ArgumentNullException
。但是,在某些情况下,更实际的做法是允许代码的使用者保留未设置的属性,同时不强制我的类需要手动实现的属性或默认构造函数,以确保这些属性永远不会得到null
。如果这是我的选择,那么我委托自己的代码必须同时检查null和empty
现在唯一的问题是,对马克的回答是什么!:) 我认为当参数为
null
时,它不应该返回false
这个函数为null
参数抛出异常,与其他BCL
类的一般行为相匹配
当序列
为空时,它确实返回false
具有null
值和将参数值作为空序列
(这是一个没有元素的序列)是有区别的。我认为当参数为null
时,它不应该返回false
这个函数为null
参数抛出异常,与其他BCL
类的一般行为相匹配
当序列
为空时,它确实返回false
有一个null
值和有一个参数值作为空序列
(这是一个没有任何元素的序列)是有区别的。我无法回答是否有合理的理论原因,但对我来说,我们处理的是两个不同的概念。我将误用语言,讨论列表,而不是枚举,但同样的论点应该适用:列表不包含任何项与列表根本不存在之间有很大区别
就个人而言,考虑到您列出的代码选项,我会选择一个您没有列出的选项(如果有一个可设置的可枚举项是有意义的,并且您的类确实可以处理任何可枚举项):
公共类Foo
{
private IEnumerable_bars=可枚举的.Empty();;
公共可数酒吧
{
获取{返回_条;}
设置{
如果(value==null)抛出新的ArgumentNullException(“value”);
_条=值;
}
}
}
i、 e.如果您不想处理空值,请不要让空值潜入您的设计中我无法回答是否有合理的理论原因,但对我来说,我们正在处理两个不同的概念。我将误用语言,讨论列表,而不是枚举,但同样的论点应该适用:列表不包含任何项与列表根本不存在之间有很大区别
就个人而言,考虑到您列出的代码选项,我会选择一个您没有列出的选项(如果有一个可设置的可枚举项是有意义的,并且您的类确实可以处理任何可枚举项):
公共类Foo
{
private IEnumerable_bars=可枚举的.Empty();;
公共可数酒吧
{
获取{返回_条;}
设置{
如果(value==null)抛出新的ArgumentNullException(“value”);
_条=值;
}
}
}
i、 e.如果您不想处理空值,请不要让空值潜入您的设计中。空值在实践中通常是一种不正确的状态,并且被绝大多数API视为不正确的状态-linq的API遵循这一点。也许您应该首先质疑为什么有空枚举,并对此加以防范。第二种方法是编写自己的扩展方法,为您提供所需的行为。过多的空检查(代码内部而不仅仅是参数检查)通常是一种代码气味 Null在实践中经常被忽略
get { return _bars; }
set { _bars = value ?? Enumerable.Empty<IBar>(); }
public class Foo
{
private IEnumerable<IBar> _bars = Enumerable.Empty<IBar>();;
public IEnumerable<IBar> Bars
{
get { return _bars; }
set {
if(value==null) throw new ArgumentNullException("value");
_bars = value;
}
}
}