首页 文章

为什么甚至可以更改私有成员,或者使用反射在C#中运行私有方法? [重复]

提问于
浏览
89

这个问题在这里已有答案:

我最近遇到了一个问题,我使用的是C#,它是通过使用reflection设置一个私有成员来解决的 .

我惊讶地发现,设置私有成员/字段以及运行私有方法是C#中允许和可能的事情 . 这不是一个如何做这些事情的问题,他们有很好的记录,我的问题是:为什么?

如果将字段/成员/方法设置为私有/内部,为什么C#作为一种语言允许将这些字段设置在范围之外?我认为这会抛出某种异常 . 如果类要求更改或设置它们不会有方法或构造函数?

9 回答

  • 56

    有时,你必须作弊 .

    它's easy to say that the class should have a setter for something if it needs to be set, but what if you can' t加一个?如果's not your class, it'是一个专有的库并且您需要解决其中的错误怎么办?我并不是说你应该做这些事情,事实上我会说你几乎肯定不应该这样,但有时候让事情发挥作用的唯一方法就是作出无耻的欺骗 . 在这些情况下,存在这些机制的事实非常有用 .

    但是,您应该始终质疑它们的使用,当然要注意,违反对象的公共API可能会导致问题进一步发生,并且可能是错误的做法 . 除了在上述情况下,它有能力改变 .

    有一点需要注意的是,C及其衍 生产环境 品具有强大的访问控制能力,但有很多OOP语言没有 . 例如,Perl 5对象完全对外部干扰开放,私有方法和数据只是按照惯例 - Perl程序员知道弄乱第三方对象的hashref可能会破坏事物,所以他们通常会赢那样做 . 同样,就像C#的反射功能一样,有时你可以通过对你不应该触摸的东西进行一些调整来解决很多问题 .

    但我再说一次,你几乎肯定不应该这样做 . 这些功能不适合日常使用 .

  • 63

    好问题 .

    我的答案是:访问修饰符和可见性是API设计的一部分 . 通过反射,您可以完全控制几乎所有内容,包括绕过API和修改低级别的数据 .

    访问修饰符可以使您的类安全,防止来自外部的意外更改 . 您可以“偶然”调用方法或访问公共成员 . 通过反思,很难保持你偶然做事 .

    如果这种低级别的反射访问是不可能的,那么我们都知道并喜欢的很多东西几乎是不可能的 .

  • 132

    私人反思要求您获得基本上完全信任 . 完全信任意味着完全信任 . 如果你're fully trusted to be doing the right thing then why shouldn'那工作?

    (事实上,私人反射的安全模型实际上比我在这里描绘的要复杂得多,但这并不影响我的观点:这种能力受制于政策 . 请参阅Security Considerations for Reflection(MSDN)以了解反思的概述和安全政策互动 . )

  • 5

    可见性修饰符不是为了安全 .

    它们只是为了使结构化API /代码库的使用更加有效 - 不会让程序员陷入困境 - 并且只暴露消费者应该关注的事情 .

  • 0

    没有反光的东西,我甚至看不到我的脸 . 好吧,我可以在视频中观看自己,但这是通过称为相机的光学设备完成的,而且它也是使用反射技术的东西 .

    如果我生病了,当医生需要X光来诊断和治疗我的疾病时,我可能已经死了,但是各种各样的反思都无法看到我的私密 . 我再也看不到自己了 .

    X射线(或类似的东西)可以看到我的内心,没有它我永远无法做到 .

    1kUml.jpg

    我宁愿说它比反思更现实 . 但是,是的,我无法用眼睛直接看到真实的我,每一个我见过的人,都是某种反思 . (为了深入思考,眼睛也会给我们现实的反映 . )

    因此,反射应该与现实相关,没有特定的观点 . 并且您可以假设消费者代码仅限于面向对象规则中的BindingFlags.Public .

    在真实的宇宙中,几乎没有什么是不可能的;我们可能和不可能之间的唯一区别在于它是否可以由人类完成,因为我们是人类 .

    看起来很危险,反射可以在程序的范围内完成所有事情,现在,出于安全原因,需要完全信任人类的逻辑 .

  • 14

    因为访问修饰符可以帮助记录您要公开的API消费者,或继承人等

    它们不是安全/访问控制机制 .

  • 3

    不可能阻止某人做到这一点 . 你可以让它变得更难,你可以强迫他们使用不安全的代码并开始盲目地设置位 . 毕竟,它允许做这样的事情 .

    这种语言的设计使你很难用脚射击并做坏事 . 但这并不能使它们变得不可能,这样做也会限制用户做一些不寻常的事情,但仍然是可取的 .

  • 6

    生产环境 代码中的一个案例:

    我们想要一个Web服务在新西兰时区工作 . 可能正确的解决方案是重写所有代码(包括一些.NET Framework序列化代码)以使用 DateTimeOffset ,但最简单的解决方案是有效地调整.NET Framework中存储当前时区的两个私有字段(通常基于注册表)电话)明确使用新西兰时区 .

    我们知道,如果.NET Framework 2.0版在处理时区时得到更新,我们可能需要重新编写代码,但目前这在 生产环境 中运行良好 .

  • 5

    反思是你如何与编译的代码进行交互 . 如果反思尊重源语言对隐私的期望,那么就需要另一种机制,就像它没有那样 . 乌龟一路下来 .

    首先假设它的作用是它的意图,然后重新评估你的假设,即做一些不同的事情是一种误导的努力,无论如何都没有人想做 .

相关问题