为什么甚至有可能改变一个私人成员,或在C#中使用reflection运行私有方法?

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

我惊讶地发现,设置一个私人成员/字段,并运行私有方法是C#允许和可能的东西。 这不是如何做这些事情的问题,他们是有据可查的,我的问题是:为什么?

如果将字段/成员/方法设置为私有/内部,为什么C#作为一种语言允许将这些字段设置在范围之外? 我认为这会抛出某种例外。 如果这个类想让他们改变或设置不会有一个方法或构造?

因为访问修饰符用于帮助logging公开给消费者或inheritance者等的API。

他们不是一个安全/访问控制机制。

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

这种语言的devise是这样的,它使你很难在脚上打自己,做坏事。 但这并不能使他们不可能,这样做也会限制用户做一些不寻常的事情,但仍然是可取的。

私下反思要求您基本上完全信任。 完全信任意味着完全信任 。 如果你完全相信做正确的事情,那么为什么不应该这样做呢?

(事实上​​,私人reflection的安全模型实际上比我在这里所描绘的要复杂得多,但是这并不影响我的观点:这个能力是以策略为准的。请参阅reflection的安全注意事项 (MSDN)了解概述反思和安全策略如何相互作用)。

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

它们仅仅是为了使结构化的API /代码库更加有效地工作 – 不会让程序员陷入低谷,而只能暴露出消费者应该关注的东西。

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

首先假定它所做的是它的意义,然后重新评估一下你的假设,那就是做一些不同的事情,而不pipe什么都不想做。

有时候,你必须作弊。

很容易说,如果需要设置某个类,那么这个类应该有一个setter方法,但是如果你不能添加一个呢? 如果不是你的课,它是一个专有库,你需要解决它的一个错误? 我并不是说你应该做这样的事情,实际上我会说你几乎肯定不应该这样做,但是有时候做某事的唯一方法就是作弊。 在这些情况下,这些机制存在的事实是非常有帮助的。

但是,你应该总是质疑他们的使用,当然要知道,违反一个对象的公共API可能会导致你更进一步的问题,可能是错误的做法。 除了前面提到的情况,只有这样才能使某些代码中的某些function无法更改。

有一点需要注意的是,C ++及其衍生产品具有较强的访问控制能力,但是有很多OOP语言却没有。 例如,Perl 5对象完全是对外界开放的,而私有的方法和数据只是按照惯例而存在的 – 一个Perl程序员知道,搞乱第三方对象的hashref可能会破坏事物,所以他们一般都会赢不这样做。 与C#的reflection能力一样,有时你可以通过对你不应该触及的东西进行一些微调来解决很多问题。

但是我再次重申,你几乎肯定不应该这样做。 这些function不适用于日常使用。

没有反思,我甚至不能看到我的脸。 好的,我可以在video中看自己,但是这是由称为相机的光学设备完成的,也是使用reflection技术的东西。

如果我生病了,当医生需要X光片来诊断和治疗我的病时,我可能已经死了,但是各种reflection都无法看到我的私生活。 我永远也看不到自己。

X光(或者类似于体层摄影的东西)可以看到我的内心,没有它我就无法做到。

1kUml.jpg

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

所以,反思应该与现实有关,没有一个特定的观点。 你可以假定消费者代码仅限于BindingFlags.Public,在面向对象的规则中。

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

反思可以在程序世界中做所有事情似乎是危险的,现在需要在人的逻辑中完全信任安全原因。

好问题。

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

访问修饰符可以使您的类免受来自外部的意外更改。 您可以拨打方法或“无意中”访问公众成员。 有了反思,很难保证你是偶然发生了事情。

而如果这种低层次的反思是不可能的,那么我们都知道和喜欢的东西实际上是不可能的。

生产代码中的一个例子:

我们希望一个networking服务在新西兰时区工作。 可能正确的解决scheme是重写我们所有的代码(包括一些.NET Framework序列化代码)以使用DateTimeOffset ,但最简单的解决scheme是有效地调整.NET Framework中存储当前时区的两个专用字段(通常基于registry呼叫)明确使用新西兰时区。

我们知道,如果.NET Framework 2.0版在处理时区时更新过,那么我们可能不得不重新编写代码,但目前这个版本在生产环境中工作正常。