当前位置: 首页 > 编程语言 > C#

Reflection是否打破了封装的原则?共享

时间:2023-04-10 12:29:11 C#

反射是否打破了封装的原则?好吧,假设我们有一个由publicclassTestClass{privatestringMyPrivateProperty{get;放;}//这是为了测试目的publicstringGetMyProperty(){returnMyPrivateProperty;然后我们尝试:TestClasst=newTestClass{MyPrivateProperty="test"};无法使用TestClass.MyPrivateProperty进行编译,因为它的保护级别是不可访问的,正如预期的那样。试过TestClasst=newTestClass();t.MyPrivateProperty="测试";并且编译再次失败并显示相同的消息。一切都很好,直到现在,我们都期待着这一点。但是然后写:PropertyInfoaProp=t.GetType().GetProperty("MyPrivateProperty",BindingFlags.NonPublic|BindingFlags.Instance);//这有效:aProp.SetValue(t,"test",null);//检查Console.WriteLine(t.GetMyProperty());在这里,我们设法更改了一个私有字段。仅使用反射就能改变对象的内部状态是不是很不寻常?编辑:感谢到目前为止的回复。对于那些说“你不必使用它”的人:那位看起来再也负担不起内部国家安全的职业设计者呢?反射通过提供对私有字段和方法的访问打破了封装的原则,但这不是绕过封装的第一个或唯一方法;有人可能会争辩说,序列化公开了一个类的所有内部数据,这些数据通常是私有的。如果消费者同意使用您定义的API,封装只是一种使设计行为更容易的技术,理解这一点很重要。如果有人选择使用反射或任何其他技术绕过您的API,他们将无法再保证您的对象会按您设计的那样运行。如果有人将null分配给私有字段,他们最好准备好在下次尝试使用您的类时捕获NullReferenceException!以我的经验,编程是关于断言和假设的。该语言断言约束(类、接口、枚举),这使得创建隔离行为更容易生成,假设消费者同意不违反这些边界。这是一个公平的断言,因为它使分而治之的软件开发方法比以前的任何技术都更容易。反思是一种工具。当它给你带来的比带走的更多时,你可以用它来打破常规。反射有某种与之相关的“痛苦”(或成本-性能、可读性、代码可靠性),因此您不会将它用于常见问题。对于常见的问题,更容易遵循面向对象的原则,这是语言的目标之一,通常被称为成功的关键。另一方面,如果没有这样的机制,有些任务是无法解决的,例如使用运行时生成的类型(但是,从.NET4.0开始,它的DLR和“它会更容易”。C#4.0中的动态“变量”。我想你可以这么说。你也可以说,CodeDom、ReflectionEmit和ExpressionTreeAPI允许你动态编写打破封装的代码。它们只是.NET提供的工具。你不必使用他们。不要忘记你必须(a)以完全信任的方式运行和(b)明确指定BindingFlags.NonPublic才能访问私有数据。这应该足够安全。你是对的,反射可以与任何数量的好的设计原则都相反,但它也可以是一个基本的构建块,可以用来支持好的设计原则——比如可以通过插件扩展的软件,控制反转等。如果你担心它代表一个问题,不应该气馁的能力,那么你可能会有所帮助。但它不如真正的语言功能方便,因此以正确的方式做事更容易。如果您认为反思应该是不可能的,那您就是在做梦!在C++中没有这样的反射。但是有一个底层的“对象模型”,编译器生成的机器代码使用它来访问对象(和虚函数)的结构。所以C++程序员可以用同样的方式打破封装。类RealClass{private:intm_secret;};classFakeClass{public:intm_notSecret;};我们可以指向一个RealClass类型的对象,只需将其转换为FakeClass并访问“私有”成员。任何受限制的系统都必须在更灵活的系统之上实现,因此它总是可以被绕过。如果反射没有作为BCL函数提供,有人可能会使用不安全的代码将它添加到库中。在某些语言中,存在封装数据的方法,因此除非以某些规定的方式,否则在该语言中不可能获取数据。但如果你能找到逃避语言的方法,作弊总是有可能的。一个极端的例子是JavaScript中的作用域变量:(function(){varx=5;myGetter=function(){returnx;};mySetter=function(v){x=v;};})();执行后,全局命名空间包含两个函数,myGetter和mySetter,这是访问x值的唯一途径。Javascript没有以任何其他方式获取x的反射能力。但是它必须在某种主机解释器中运行(比如在浏览器中),所以一定有一些可怕的方法来操纵x。插件中的内存损坏错误可能是偶然发生的!可以说反射也会破坏继承和多态。当不是为每个对象类型提供其自己的重载方法版本时,您有一种方法可以在运行时检查对象类型并切换到每个对象类型的特定行为。尽管如此,反思仍然是一个很好的工具。有时您需要使用私有构造函数实例化一个对象,因为这是最佳做法,并且您不能更改类实现(关闭库,无法再联系作者)。或者你可能想在一个地方对各种对象执行一些辅助操作。或者您可能希望对某些类型执行日志记录。当反射确实有助于不造成任何损害时就是这种情况。这是Reflection提供的部分功能,但我认为这不是它的最佳用途。它只有在完全信任的情况下才有效。封装原则由您的API保留,但反射为您提供了一种解决API的方法。任何使用反射的人都知道他没有正确使用你的API!不,它没有例外。反射允许您这样做,并且在某些情况下您正在做的事情可能会有用,在许多其他情况下它只会使您的代码成为一个定时炸弹。反射是一种工具,它可以被使用或滥用。关于编辑后的问题:答案是否定的。API设计者可以尽其所能,投入大量精力来公开一个干净的接口,并通过使用反射来查看他的API过度滥用。工程师可以制造一台完美的洗衣机,既安全又不会给你电击等,但是如果你用锤子敲它直到看到电缆,如果你受到电击,没有人会责怪工程师:d反射帮助你保持代码干净。例如,当你使用hibernate时,你可以直接将私有变量绑定到DB值,而无需编写你不需要的不必要的setter方法。从这个角度来看,反射可以帮助你保持封装。以上是C#学习教程:反射是否打破了封装原则?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: