在C#中进行反思的理由
我想知道Ccode中反射的适当性。例如,我编写了一个函数,该函数遍历给定源对象的属性并创建指定类型的新实例,然后将具有相同名称的属性值从一个复制到另一个。我创建此文件是为了将数据从一个自动生成的LINQ对象复制到另一个对象,以解决LINQ中多个表缺乏继承的问题。
但是,我不禁会认为这样的代码确实是"欺骗",即,不是使用提供的语言构造来达到给定的目的,而是让我们规避它们。
这种代码在多大程度上可以接受?有什么风险?此方法的合法用途是什么?
解决方案
回答
可能只是我一个人,但是我要采用的方法是在运行时使用反射创建一个代码生成器,这有点昂贵且无法输入。创建将根据最新代码生成并以强类型方式复制所有内容的类将意味着我们将在构建时捕获这些错误。
例如,生成的类可能如下所示:
static class AtoBCopier { public static B Copy(A item) { return new B() { Prop1 = item.Prop1, Prop2 = item.Prop2 }; } }
如果任何一个类都没有属性或者其类型发生更改,则代码不会编译。另外,时代有了很大的改善。
回答
我同意,它给了我它有效的感觉,但是感觉就像是一种骇客的感觉。我会尽量避免反射。重构包含反射的代码后,我被烧了很多遍。代码可以很好地编译,甚至可以运行测试,但是在特殊情况下(测试未涵盖),由于我在反射代码插入的对象之一中进行重构,因此程序耗费了运行时间。
示例1:在OR映射器中进行反射,我们可以更改对象模型中属性的名称或者类型:消耗运行时间。
示例2:我们在SOA商店中。 Web服务已完全解耦(或者我们认为如此)。它们具有自己的一组生成的代理类,但是在映射中,我们决定节省一些时间,然后执行以下操作:
ExternalColor c = (ExternalColor)Enum.Parse(typeof(ExternalColor), internalColor.ToString());
在幕后,这也是反思,但由.net框架本身完成。现在,如果我们决定将InternalColor.Grey重命名为InternalColor.Gray,会发生什么?一切看起来都不错,它可以很好地构建,甚至可以很好地运行..直到那天,一个愚蠢的用户决定使用颜色Gray ...那时,映射器将崩溃。
回答
有时使用反射可能会有点麻烦,但在很多时候,它只是最出色的代码工具。
查看.Net属性网格,任何使用Visual Studio的人都会熟悉它。我们可以将其指向任何对象,它将产生一个简单的属性编辑器。这使用了反射,实际上VS的大多数工具箱都使用反射。
查看通过反射加载的单元测试(至少在NUnit和MSTest中)。
反射允许来自静态语言的动态样式行为。
它真正需要做的一件事就是键入Ccompiler已经支持的鸭子:我们可以" foreach"任何看起来像" IEnumerable"的东西,无论它是否实现了接口。我们可以在任何具有称为"添加"方法的类上使用C#3集合语法。
在需要动态样式行为的任何地方使用反射,例如,我们有一个对象集合,并且想要检查每个对象上的相同属性。
对于动态类型,风险是相似的。编译时异常会成为运行时异常。代码并不安全,因此我们必须做出相应的反应。
.Net反射代码非常快,但不像显式调用那样快。
回答
我最近在Cfor中使用了反射来查找特定接口的实现。我编写了一个简单的批处理样式的解释器,该解释器根据类名针对计算的每个步骤查找"操作"。反映当前的名称空间,然后弹出可以执行Execute()的IStep接口的正确实现。这样,添加新的"操作"就像创建新的派生类一样简单,无需将其添加到注册表中,甚至更糟:忘记将其添加到注册表中...
回答
反思是一个我不能没有的绝妙工具。它可以使编程变得更加容易和快捷。
例如,我在ORM层中使用了反射,以便能够为表中的列值分配属性。如果不是为了反思,我必须为每个表/类映射创建一个复制类。
至于上面的外部颜色异常。问题不在于Enum.Parse,而是编码器没有捕获适当的异常。由于已解析字符串,因此编码人员应始终假定该字符串可以包含不正确的值。
相同的问题适用于.Net中的所有高级编程。 "拥有权利的同时也被赋予了重大的责任"。使用反射可以为我们提供强大的功能。但是请确保我们知道如何正确使用它。网上有数十个示例。