Jon*_*tte 7 c# reflection attributes
我有许多类型需要提供与外部世界通信的自定义函数。例如,我可能有一个 Widget 和一个 Sprocket,当来自我无法控制的世界的数据到达并说“制作一个 Widget”时,我需要调用 Widget.Create() 函数。如果世界说“制作一个锤子”,那么我需要返回“锤子不存在”错误。然而,world-representation 和 type-name 之间的映射不是 1:1,所以我不能简单地使用反射来直接查找类型名称——我需要一个表。(事实上,“名称”可能是一个特定的整数值。)
我了解如何使用从世界表示映射到类名称的预定义表(或字典)。我还了解如果可能的类集发生更改,如何在运行时扩展/更改此表。(由于规则更改,或应用程序的动态加载部分,或其他原因。)
然而,所有这些都需要重复——我必须实现我的类,然后,在代码中的其他地方,记住添加一个“这个类在外部世界有这个名称”的实例。这有点代码味道,因为将来的某个时候我会编写一个新类(或删除一个旧类)并忘记更新表,然后花时间调试为什么它不能正常工作。
我想我可以在每个类中使用一个静态成员,该成员将自身注册到全局表中:
public static Registration Me = new Registration(typeid(MyClass), "My Name");
Run Code Online (Sandbox Code Playgroud)
不幸的是,静态字段在类中的某些函数被执行/访问之前不会被初始化,因此它不会在启动时运行。(静态构造函数也有类似的限制,而且运行时的开销甚至更大!)
下一个想法是用一个自定义属性来装饰该类,该属性表示“在表中注册该类”。
[Register("My Name")]
class MyClass : .... {
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,“Register”属性不知道它附加到哪个类——只有 MyClass 类知道它具有 Register 属性。(这让我很生气,因为在很多很多情况下,如果属性知道它们附加在哪里,那就太方便了。但这是一个旁白!)
因此,我能想到的最不糟糕的实现是使用反射迭代所有程序集的所有类型,并检查它们是否具有此属性,如果有,则将它们注册到表中。我们可以说,这既不优雅也不高效。
有没有更好的方法来自动注册类,而无需使用中央注册表更新其他源文件?
我检查过其他资源(对 CLR 和 IL 的内部结构非常了解),看来这是 CLR 和 C# 语言中的一个漏洞。根本没有直接的方法可以使事情在程序集加载或应用程序域准备时自动发生。遍历类型并找到我感兴趣的类型是最不坏的方法。事实上,属性并不总是在某些代码需要它们之前创建,所以我也不能使用带有类型参数的属性构造函数来自动注册!
这当然不太好,因为如果有八个不同的代码段,每个代码段都有自己想要执行的注册类型,那么每个代码段都必须迭代所有类型并自行进行检查。解决这个问题的唯一方法是放弃模块化,并将发生在类型上的所有不同“事物”集中到应用程序启动时的单个遍历所有类型循环中。不过,第三方库(包括 MEF)仍然不会进入这个循环,因此这里只是不可避免的一大块开销,或者是不可避免的重复部分——这是我作为开发人员的选择。
| 归档时间: |
|
| 查看次数: |
2725 次 |
| 最近记录: |