2008-09-06 53 views
10

我想知道在C#代码中反射的恰当性。例如,我编写了一个函数,它遍历给定源对象的属性并创建指定类型的新实例,然后将具有相同名称的属性值从一个复制到另一个。我创建了这个将数据从一个自动生成的LINQ对象复制到另一个,以解决LINQ中多个表的继承问题。在C中反射的理由#

但是,我不禁想到像这样的代码真的是“作弊”,即不是使用提供的语言结构来实现给定的目标,而是允许您规避它们。

这种代码在什么程度上可以接受?有什么风险?这种方法的合理用途是什么?

回答

1

它可能只是我,但我的方式是通过创建一个代码生成器 - 在运行时使用反射是有点昂贵和无类型。创建根据最新代码生成的类并以强类型方式复制所有内容将意味着您将在构建时捕获这些错误。

例如,生成的类可能是这样的:

static class AtoBCopier 
{ 
    public static B Copy(A item) 
    { 
     return new B() { Prop1 = item.Prop1, Prop2 = item.Prop2 }; 
    } 
} 

如果任一类不具备的特性或它们的类型改变,代码不能编译。另外,这个时代有很大的改善。

2

我同意,它给我的它的作品,但它感觉像一个黑客感觉。尽可能避免反思。在重构了代码中的代码后,我被烧了很多次。代码编译得很好,测试甚至可以运行,但是在特殊情况下(测试没有涉及),程序由于重构了反射代码中的一个对象而重新运行。

示例1: OR映射器中的反射,您更改对象模型中属性的名称或类型:抛出运行时。

示例2:您身处SOA商店。 Web服务是完全分离的(或者你认为)。他们有自己的一套生成的代理类,但在映射你决定节省一些时间和你这样做:

ExternalColor c = (ExternalColor)Enum.Parse(typeof(ExternalColor), 
              internalColor.ToString()); 

在幕后,这也是反映,由.NET Framework本身完成。现在如果您决定重命名InternalColor.GreyInternalColor.Gray会发生什么情况?一切看起来都不错,它建立的很好,甚至可以正常运行..直到一天愚蠢的用户决定使用灰色......在这一点上映射器将炸毁。

8

有时使用反射可能有点破解,但很多时候它只是最奇妙的代码工具。

看看.Net属性网格 - 任何使用过Visual Studio的人都会熟悉它。你可以将它指向任何对象,它会产生一个简单的属性编辑器。这使用反射,实际上VS的大部分工具箱都是这样。

看看单元测试 - 它们是通过反射加载的(至少在NUnit和MSTest中)。

反射允许来自静态语言的动态样式行为。

它真正需要的一件事就是鸭子打字 - C#编译器已经支持:你可以foreach任何看起来像IEnumerable的东西,不管它是否实现接口。您可以在任何具有名为Add的方法的类上使用C#3集合语法。

使用反射,无论你需要动态式的行为 - 例如,你有对象的集合,并要检查每个相同的属性。

动态类型的风险类似 - 编译时异常变成运行时异常。你的代码不是'安全'的,你必须做出相应的反应。

.Net反射代码非常快,但并不像显式调用那样快。

+0

如果有人问我有什么反思和反思,这会是一个合适的答案吗? – 2014-08-04 19:56:26

1

我最近在C#中使用反射来查找特定接口的实现。我编写了一个简单的批处理样式解释器,根据类名查找每个计算步骤的“操作”。反映当前的命名空间,然后弹出我可以执行()编辑的IStep接口的正确实现。这样一来,增加了新的“行动”的创建一个新的派生类一样简单 - 没有必要将其添加到注册表,甚至更糟糕:忘记将其添加到注册表...

2

反思是一个奇妙的工具我不能没有。它可以使编程更容易和更快。

例如,我在我的ORM层中使用了反射,以便能够从表中分配具有列值的属性。如果不是反射,我不得不为每个表/类映射创建一个副本类。

至于上面的外部颜色异常。问题不是Enum.Parse,但编码器没有捕获到适当的异常。由于字符串被解析,编码器应该总是假定字符串可以包含不正确的值。

同样的问题适用于.Net中的所有高级编程。 “拥有权利的同时也被赋予了重大的责任”。使用反射给你很大的力量。但请确保您知道如何正确使用它。网上有很多例子。

0

反射使得它非常容易实现的,其中的插件DLL文件在运行时自动加载(在编译时没有明确的链接)的插件架构。

这些可以扫描实现/扩展相关接口/类的类。然后可以使用反射来按需实例化这些实例。