我IEnumerable<A>
只含有B的对象。
我会质疑这个关于你的变量的声明。您已指定它是IEnumerable<A>
,但它仅包含B
的实例。这样做的目的是什么?如果您在任何情况下明确只需要B
的实例,则最好是IEnumerable<B>
,因为它可以防止在编译时可能遇到的问题。
考虑下面的,我会想象,你可能有一些类似代码:
var setOfA = // Get a set of A.
DoSomethingWithA(setOfA);
var instanceOfB = GetInstanceOfB(setOfA);
在这种情况下,我能理解的IEnumerable<A>
是完全有效的,当你想进行后者的操作,除了,GetInstanceOfB
。让我们想象一下,这个定义是:
B GetInstanceOfB(IEnumerable<A> setOfA)
{
return // The answer to your question.
}
现在,最初的问题,我希望你看到的,是你把你所有的卡上的概念,您的列表(setOfA
在我的例子),总是只打算包含B
的实例。虽然您可以保证从您的开发人员的角度来看,编译器可以不做这样的假设,但只能保证setOfA
(列表)是IEnumerable<A>
,并且其中存在潜在的问题。
综观提供的答案(所有这些都是非常有效的[@VirtualBlackFox是最安全的答案]给你的想法):
我IEnumerable<A>
只含有B的对象。
,如果在将来的某个变化,setOfA
,还包含C
实例(的A
未来潜在的子类)是什么。鉴于这样的回答:
list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something");
如果setOfA
居然是:[C B B]
。您可以看到,明确演员(B)b
将导致InvalidCastException
被引发。由于Single
操作的性质,它将继续枚举,直到第一个实例失败谓词(PropertyThatOnlyExistOnB == "something"
),或抛出异常为止。在这种情况下,可能会抛出异常,这是意外的,并且可能未处理。这样的回答,是类似于:
list.Cast<B>().Single(b => b.PropertyThatOnlyExistOnB == "something");
给出这样的回答:
list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something")
在相同的情况下,异常往往发生的NullReferenceException
抛出实例,因为C
实例不能安全地输入投到B
。
现在,请不要误会我的意思,我是而不是选那些答案,因为我说他们是完全有效的,因为你的问题的职权范围。但在代码更改的情况下,那些完全有效的答案成为潜在的未来问题。
给出这样的回答:
list.OfType<B>.Single(b => b.PropertyThatOnlyExistOnB == "something");
这可以让你安全地类型转换为的A
,它们事实上B
一个潜在的子集,编译器可以保证你的断言只被上IEnumerable<B>
使用。
但是,这会让我发现代码中的关头试图处理您的IEnumerable<A>
,但执行的操作是您真正需要的IEnumerable<B>
。在这种情况下,你不应该重构这个代码可能有一个明确的方法:
B GetMatchingInstanceOfB(IEnumerable<B> setOfB)
{
if (setOfB == null) throw new ArgumentNullException("setOfB");
return setOfB.Single(b => b.PropertyThatOnlyExistOnB == "something");
}
的方法设计的变化将确保自己只能明确接受一组有效的B
,而你不知道不必担心你在这种方法中的演员。该方法仅负责匹配B
的单个项目。
当然,这意味着你需要把你赶出去,以不同的水平,但仍然是更明确:
var b = GetMatchingInstanceOfB(setOfA.OfType<B>());
我也假设你有足够的错误处理到位的情况下,在所有实例为B
的情况下谓词将失败,例如,多于一个项目满足PropertyThatOnlyExistOnB == "something"
。
这可能是一个无意义的评论你的代码的咆哮,但我认为这是值得考虑的可能出现的意外情况,以及如何调整变量可以为你节省潜在的头痛在未来。
+1打我到它30秒:) – MatthewKing
不错,干净,非常感谢! –