我最近遇到了一个使用C#时的问题,通过使用反射来设置私有成员后,问题得以解决。
我对于在C#中设置私有成员、运行私有方法这些操作是允许且可行的感到惊讶。这不是关于如何执行这些操作的问题,它们已经有很好的文档说明。我的问题是:为什么?
如果将字段/成员/方法设置为私有或者友元,为什么C#编程语言允许外部对这些字段进行设置?我认为这应该会引发某种异常。如果类希望更改或设置它们,难道不应该提供一种方法或构造函数吗?
我最近遇到了一个使用C#时的问题,通过使用反射来设置私有成员后,问题得以解决。
我对于在C#中设置私有成员、运行私有方法这些操作是允许且可行的感到惊讶。这不是关于如何执行这些操作的问题,它们已经有很好的文档说明。我的问题是:为什么?
如果将字段/成员/方法设置为私有或者友元,为什么C#编程语言允许外部对这些字段进行设置?我认为这应该会引发某种异常。如果类希望更改或设置它们,难道不应该提供一种方法或构造函数吗?
unsafe
意味着即使没有反射,你也可以访问C#数据类型的私有字段。(我不敢尝试) - Patashu防止某人这样做是不可能的。您可以增加难度,迫使他们使用不安全的代码并开始盲目地设置位。 毕竟,这是他们的程序/机器,他们允许这样做。
语言的设计使您很难自毁而犯错。 但这并不是不可能的,这样做也会限制用户进行一些不寻常但仍然可取的事情。
Reflection
修改数据可能会导致不稳定性(尽管我已经做过):D - Mike Perrenoud私有反射需要您被授予基本完全的信任。完全信任意味着完全信任。如果您被完全信任能够做正确的事情,那么为什么不应该起作用呢?
(实际上,私有反射的安全模型比我在这里勾画的要复杂得多,但这并不影响我的观点:这种能力受制于策略。请参阅 Reflection 的安全注意事项 (MSDN) 了解反射和安全策略如何相互作用)
可见性修饰符并不是为了安全而存在。
它们的存在只是为了使得与结构化API/代码库一起工作更加高效 - 不会让程序员被琐碎的东西拖累 - 并且只暴露消费者需要关注的内容。
反射是您与已编译代码交互的方式。如果反射遵守源语言对隐私的期望,那么就需要另一种机制,该机制不遵循这些期望。一切皆为龟。
首先假设它所做的就是它应该做的,然后重新评估您的假设,即这是一个误导性的努力,试图做一些任何人都不想做的事情。
我甚至没有办法透过反光物体看到我的脸。好吧,我可以在视频中看到自己,但那是通过被称为相机的光学设备完成的,它也使用了反射技术。
如果我生病了,医生需要用X光来诊断和治疗我的疾病时,所有种类的反射都无法看到我私人的部分。而且我也永远无法看到自己。
X光(或类似于层析成像的)可以观察我的内部,而我没有它就无法做到这一点。
我更愿意说它比反射更现实。但是是的,我不能用眼睛直接看到真正的我,我曾经看到的每一个我,都是某种反射形式。(深入思考,眼睛也给我们反映现实的反射。)
因此,反射应该与现实有关,没有特定的视角。您可以假设消费者代码受到BindingFlags.Public的限制,符合面向对象编程的规则。
在真实的宇宙中,几乎没有什么是不可能的;对于我们来说,可能和不可能之间唯一的区别是是否可以被人类完成,因为我们是人类。
看起来反射可以在程序的宇宙中做任何事情,现在出于安全原因需要完全信任它,在人类的逻辑中这是危险的。
很好的问题。
我的答案是:访问修饰符和可见性是API设计的一部分。通过反射,您可以完全控制几乎所有内容,包括绕过API并在低级别上修改数据。
访问修饰符可以使您的类免受外部意外更改的影响。您可能会“意外地”调用方法或访问公共成员。通过反射,很难维护您是出于偶然而这样做的。
如果反射中的低级别访问不可能,我们所熟悉和喜欢的许多东西将几乎不可能实现。
生产代码中的一个案例:
我们希望一个 Web 服务在新西兰时区工作。可能正确的解决方案是重写所有代码(包括一些 .NET Framework 序列化代码)以使用 DateTimeOffset
,但最简单的解决方案是有效地调整 .NET Framework 中存储当前时区的两个私有字段(通常基于注册表调用)以明确使用 NZ 时区。
我们知道,如果 .NET Framework 版本 2.0 在处理时区方面进行更新,我们可能需要重新设计我们的代码,但目前这在生产中运行良好。