我打算为我的新项目使用动态关键字。但在介入之前,我想了解使用动态关键字而不是反射的优缺点。
在专业人士的位置,我可以找到动态关键字:
虽然与使用动态关键字相关的负面影响,但我听到的却是:
请帮助我了解我遇到的利弊是否合情合理?
答案 0 :(得分:98)
请帮助我了解我遇到的利弊是否合情合理?
我对你的优点和缺点的关注是,其中一些没有解决使用反射和使用动态之间的差异。这种动态类型会导致在任何动态类型系统的运行时都没有捕获的错误。反射代码与使用动态类型的代码一样容易出错。
不要在利弊方面考虑它,而是以更中性的方式思考它。我要问的问题是“使用Reflection和使用动态类型之间的差异是什么?”
首先:使用Reflection,您可以完全您要求的内容。使用动态,您可以获得如果在编译时获得类型信息,C#编译器将完成的工作。这些可能是两个完全不同的东西。如果您有一个特定方法的MethodInfo,并且您使用特定参数调用该方法,那么即被调用的方法,period。如果你使用“动态”,那么你要求DLR在运行时解决C#编译器关于哪种方法是正确调用的意见。 C#编译器可能会选择与您实际需要的方法不同的方法。
第二:使用Reflection,您可以(如果您的代码被授予适当的高级别信任)进行私人反思。您可以调用私有方法,读取私有字段等。这样做是不是一个好主意,我不知道。这对我来说当然是危险和愚蠢的,但我不知道你的申请是什么。使用动态,您将获得从C#编译器获得的行为;私有方法和字段不可见。
第三:使用Reflection,您编写的代码看起来像机制。看起来您正在加载元数据源,提取某些类型,提取一些方法信息,以及通过方法信息调用接收器对象上的方法。该方式的每一步看起来都像机制的操作。通过动态,每一步都看起来像业务逻辑。您在接收器上调用方法的方式与在任何其他代码中执行方法相同。什么是重要的?在某些代码中,该机制实际上是最重要的。在某些代码中,机制实现的业务逻辑是最重要的。选择强调正确抽象级别的技术。
第四:绩效成本不同。使用Reflection,您不会获得任何缓存行为,这意味着操作通常较慢,但维护缓存没有内存成本,并且每个操作的成本大致相同。使用DLR,第一次操作确实非常慢,因为它进行了大量的分析,但是分析被缓存并重用。这会消耗内存,以换取在某些情况下后续调用中增加的速度。我不知道你的应用程序的速度和内存使用的正确平衡是什么。答案 1 :(得分:25)
可读\可维护代码
我的经历当然是对的。
更少的代码行。
不显着,但会有所帮助。
影响应用程序性能。
非常轻微。但是,甚至没有接近反射的方式。
动态关键字在内部是Reflection的包装。
完全不真实。动态关键字利用动态库运行时。
[编辑:根据以下评论进行更正]
似乎动态语言运行时确实使用了Reflection,性能改进仅归功于缓存技术。
动态类型可能会成为难以找到错误的滋生地。
这可能是真的;这取决于你如何编写代码。您正在有效地从代码中删除编译器检查。如果您的测试覆盖率良好,这可能无关紧要;如果没有,那么我怀疑你会遇到问题。
影响与以前的.NET版本的互操作性
不正确。我的意思是你将无法针对旧版本编译你的代码,但如果你想这样做,那么你应该使用旧版本作为基础并上传它而不是相反。但是,如果您想使用.NET 2库,那么只要在app.config / web.config中包含声明,就不应该遇到太多问题。
您缺少的一个重要职业是改进了与COM / ATL组件的互操作性。
答案 2 :(得分:12)
动态和反射之间有4个很大的区别。以下是对其的详细说明。参考http://www.codeproject.com/Articles/593881/What-is-the-difference-between-Reflection-and-Dyna
点1.检查VS调用
Reflection可以做两件事,一件是它可以检查元数据,二是它还具有在运行时调用方法的能力。而在Dynamic中我们只能调用方法。因此,如果我正在创建像visual studio IDE这样的软件,那么反射就是最佳选择。如果我只想从我的c#代码中动态调用,那么动态是最好的选择。
第2点。私人与公开调用
您无法使用动态调用私有方法。在反射中,它可以调用私有方法。
第3点。缓存
Dynamic在内部使用反射,它还增加了缓存优势。因此,如果您只想动态调用一个对象,那么动态是最好的,因为您可以获得性能优势。
第4点。静态类
动态是特定于实例的:您无权访问静态成员;你必须在这些场景中使用Reflection。
答案 3 :(得分:4)
在大多数情况下,使用dynamic关键字不会导致有意义的更短代码。在某些情况下,它会;这取决于提供商,因此这是一个重要的区别。您可能永远不应该使用dynamic关键字来访问纯CLR对象;这个好处太小了。
动态关键字破坏了自动重构工具,使高覆盖率的单元测试变得更加重要;毕竟,当你使用它时,编译器没有检查任何东西。当您使用非常稳定或固有动态类型的API进行互操作时,这并不是一个问题,但如果您使用关键字动态来访问其API可能在将来发生变化的库(例如您自己编写的任何代码),那么这一点尤其令人讨厌)。
在有意义的地方谨慎使用关键字,并确保此类代码具有充足的单元测试。不要在不需要的地方或类型推断(例如var
)也可以这样做的地方使用它。
编辑: 您在下面提到您正在为插件执行此操作。 Managed Extensibility Framework的设计考虑到了这一点 - 关键字dynamic
和反射可能是更好的选择。
答案 4 :(得分:2)
如果您使用动态专门进行反射,那么您唯一关心的是与先前版本的兼容性。否则它会胜过反思,因为它更具可读性和更短。无论如何,你都会失去强烈的打字和(某些)表现。
答案 5 :(得分:1)
使用Reflection时,除了与旧.NET版本的互操作性之外,我还能看到使用动态的所有缺点:
影响应用程序性能
虽然它确实影响了性能,但使用Reflection也是如此。从我记得DLR或多或少使用Reflection第一次访问给定类型的动态对象的方法/属性并缓存类型/访问目标对,以便以后访问只是在缓存中查找,使其更快然后反思
动态关键字在内部是Reflection
的包装器
即使这是真的(见上文),这将是一个负面因素?它是否包装反射不应影响您在任何重要事项中的应用。
动态类型可能会成为难以找到错误的滋生地
虽然这是真的,只要你谨慎使用它,它就不应该是一个很大的问题。此外,你基本上用它作为反射的替代品(也就是说,当你想通过反射访问某些东西时,你只使用动态的最短时间),这种错误的风险不应该高得多,如果你使用反射来访问你的方法/属性(当然,如果你把一切都变得动态,那么它可能会成为一个问题)。
影响与以前的.NET版本的互操作性
为此你必须自己决定对你有多大关注。