所以我没有找到任何优雅的解决方案,无论是谷歌搜索还是整个stackoverflow。我想我手中有一个非常具体的情况,无论如何它是这样的:
我有一个我无法控制的对象结构,因为我从外部 WS 接收到这个结构。这是一个相当大的对象,具有各种级别的字段和属性,并且在任何级别中,此字段和属性都可以为空,也可以不为空。您可以将此对象视为贫血模型,它没有行为,只有状态。
出于这个问题的目的,我将为您提供一个模拟我的情况的简化示例:
Class A
PropB1
PropC11
PropLeaf111
PropC12
PropLeaf112
PropB2
PropC21
PropLeaf211
PropC22
PropLeaf221
因此,在我的代码中,我必须访问不同级别的许多这些属性,以进行一些数学运算以计算我需要的内容。基本上对于我必须做的每种类型的计算,我必须测试我需要的每个级别的属性,以检查它是否不为空,在这种情况下,我将返回(十进制)0,或任何其他默认值,具体取决于业务逻辑。
我必须与之相关的数学示例:
var value = 0;
if (objClassA.PropB1 != null && objClassA.PropB1.PropC11 != null) {
var leaf = objClassA.PropB1.PropC11.PropLeaf111;
value = leaf.HasValue ? leaf.Value : value;
}
非常重要的是,这种结构的叶属性始终是基元,或者可以为空的基元,在这种情况下,我会给予适当的处理。这是我必须为我需要的每个属性执行的“逻辑”,有时我必须使用其中的一些属性。实际结构也相当大,所以我需要做的验证次数对于每个必要的属性也会更大。
现在,我想出了一些想法,我认为它们都不理想:
- 创建方法来收集属性,其中将抽象任何必要的验证或获取默认值的逻辑。缺点是,在我看来,它会有相当多的重复代码,因为验证和默认值对于某些字段组是相似的。
- 创建一个通用方法,它接收一个对象,以及一个访问所需字段的 Lamba 函数。此方法将尝试执行该函数并返回其结果,并且在出现 NullReferenceException 的情况下,它将返回一个默认值。这个的好处是它非常通用,我只需要传递 lambdas 来访问属性,并且该方法可以处理任何问题。它的缺点是我正在使用 try -> catch 来控制逻辑,这不是它的目的,并且对于最终会对其进行维护的其他程序员来说,代码可能看起来令人困惑。
- 空对象模式,我猜这将是最优雅的解决方案。如果是正常情况,它将具有所有优点。但问题是为这个结构提供空对象的影响。只是为了提供更多背景信息,我正在开发的软件与政府的服务集成,我正在使用的结构(在政府的规范中)有一些字段,其中 null 有一些不同于默认值,如“0”。此外,该规范不时更改,并且再次生成类,并且我必须进行创建 Null 对象的后处理也需要维护,这对我来说似乎有点危险。
我希望我说得够清楚。
提前致谢。
解决方案
这是对我如何解决问题的回应,基于接受的答案。
我对 C# 很陌生,这种相关的讨论确实帮助我在许多方面提出了一个优雅的解决方案。我仍然有一个问题,即根据代码的执行位置,它使用.NET 2.0,但我也找到了解决这个问题的方法,我可以在其中定义扩展方法:https ://stackoverflow.com/a/707160/649790
对于解决方案本身,我发现这是最好的:http: //www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad
我基本上可以通过这种方式访问属性,然后进行数学运算:
objClassA.With(o => o.PropB1).With(o => PropC11).Return(o => PropLeaf111, 0);
对于我需要的每个属性。它仍然不仅仅是:
objClassA.PropB1.PropC11.PropLeaf111
当然,但是到目前为止我找到的任何解决方案都要好得多,因为我不熟悉扩展方法,所以我真的学到了很多东西。
再次感谢。