【问题标题】:Why are Reflection's GetProperty() or GetField() not instance or extension methods?为什么反射的 GetProperty() 或 GetField() 不是实例或扩展方法?
【发布时间】:2017-08-29 15:24:32
【问题描述】:

我对 C# 中的反射相当陌生,我想我知道如何使用它来解决一些问题。

但是,让我感到困惑的是 GetProperty() 或 GetField() 等方法的语法。

要获取实例字段,您必须执行typeof(MyClass).GetField("fieldName").GetValue(myClassInstance)。这不是最直接的事情。

使用扩展方法之类的方法获取实例字段或属性不是更有意义吗?比如:

myClassInstance.GetField("fieldName").Value

然后将前面的示例用于静态字段/属性/方法等内容。

感觉比第一个例子更自然,你必须传递你的类实例。

再说一次,我是 Reflection 的新手,所以我可能忽略了一些缺点。

【问题讨论】:

  • 字段元数据是类的属性,而不是实例的属性。使用您的语法,您需要一个实例来获取有关该字段的信息。
  • 另一个原因是扩展方法并不总是 c# 的一部分,所以当第一次编写反射代码时,它们显然不能使用扩展方法...
  • 那么,您使用反射读取字段的频率如何?这通常不是一个非常常见的模式。是的,Object 上可能有一个扩展方法到GetFieldValue(string name),你可以自己写一个。任何人都可以告诉您它在框架中不存在的唯一原因是设计者认为它不是一个有价值(足够)的功能。
  • 就个人而言,我更喜欢将反射方法与标准对象模型分开。反射打破了关于访问修饰符等的常规规则。如果反射是每个对象公共 API 的标准部分,那么制作 private 的意义何在?
  • 其实反射入口点在每个实例obj.GetType().Get...上都有。

标签: c# .net reflection


【解决方案1】:

要获取实例字段,您必须执行typeof(MyClass).GetField("fieldName").GetValue(myClassInstance)。这不是最直接的事情。

嗯,不完全是。要获取实例字段,您必须执行fieldInfo.GetValue(myClassInstance)

当然,从myClassInstanceMyClass 的编译时(实际上是编码时)知识开始,意味着您获得fieldInfo 的方式是通过typeof(MyClass).GetField("fieldName"),但接下来就可以了myClassInstance.fieldName 或者如果需要演员 ((MyClass)myClassInstance).fieldName,这更容易、更快、更不容易出错。

当我们不能只做myClassInstance.fieldName 时,反射很有用,因为我们只在运行时获得了Type 和/或FieldInfo。那么我们需要的是灵活性,让我们能够处理各种我们在编译时知道或不知道的情况。

现在,创建 myClassInstance.GetField("fieldName").Value 可以工作的类型和方法(实例或扩展)是完全可能的。但这会有多大用处?

首先,如上所述,如果我们在编译时知道myClassInstance 的类型是没有意义的。而且,这个GetField() 方法应该适用于什么类型?编译时类型显然没有意义,但它应该是运行时类型(通过调用GetType() 可以找到的类型)?这可能是最常用的类型,但我们可能希望强制查找特定的基本类型(或接口类型——显然不是在查找字段的情况下,而是可能用于方法、属性和事件),所以我们在这方面失去了灵活性,只在当前满足的特定情况下获得了灵活性。

因此,虽然在某些情况下添加此功能会很有用,但在其他情况下仍需要当前 API。它只能是一个方便的 API,而不是主要的。

事实上,我们有方便的 API,因为这是 dynamic 给我们的。

((dynamic)myClassInstance).fieldName

这允许我们在myClassInstance 的运行时类型上获取或设置名为fieldName 的字段,并且通常比您建议的API 更方便。它还具有单独的编译时类型的优点(在运行时dynamic 与编译时object 相同,编译器在编译时通过使用后期绑定而不是早期绑定来区别对待它)。因此,我们在object 上没有公开的表面,其中包含用于非常罕见的情况的方法(实际上是应该很少见的情况;返回类型的速度、类型以及最重要的防范来自类型安全的不正确性将尽可能受到青睐)并且也将dynamic作为返回类型,这很好,因为当我们获得这种方式时,我们更有可能想要做更多这种后期绑定第一次实例化。

【讨论】:

  • 这是一个绝妙的答案。老实说,我几乎没用过dynamic。现在我看到它是一个如此强大的工具,但显然,只有在严格要求时才应该使用它,因为它对拼写错误非常敏感。感谢您的详细解释!
  • 错别字并不是最糟糕的,因为它们往往会在您第一次测试时被发现。更复杂的情况是,您发现自己试图通过 dynamic 在不支持该方法的对象上使用方法,但随后无法立即看到为什么将此类对象传递给使用 @987654346 的方法@ 因为这个决定在调用链中倒退了几步,这真的很伤人。还有一些事情是它无法处理的(任何不能装箱的东西)。确实,它提供了一种后期绑定语言的所有优点,但却以一种缺点为代价。
猜你喜欢
  • 1970-01-01
  • 2010-10-26
  • 2014-08-11
  • 2010-09-29
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 2019-09-23
相关资源
最近更新 更多