我看到很多C#,.net问题在这里使用反射解决了。对我来说,很多它们看起来像是以优良设计(OOP)为代价来弯曲规则。许多解决方案看起来不可维护且“脚本化”。
一般来说,使用反射是一种好习惯吗? 有没有什么东西只能通过反思来解决?
编辑:
请举例说明反射是唯一的好解决方案。
答案 0 :(得分:44)
示例:
反射是一种工具,就像“投掷”一样。你应该到处使用扔?没有!那么使用抛出的代码气味是什么?
答案 1 :(得分:14)
对我来说,很多人看起来像弯腰 以良好设计为代价的规则 (OOP)。许多解决方案看起来 不可维护和“脚本”。
老实说,“好的设计”与OOP没什么关系。我想说一个更大的设计气味要关注的是,良好的设计与OOP完全相同。如果没有OOP,我们就无法拥有良好的设计,并且如果没有成为优秀的设计,我们就无法遵循OOP的规则。这几乎和人们对“气味”的痴迷一样糟糕。程序员应该使用他们的大脑,而不是他们的鼻子。
使用反射是一种很好的做法 一般?有没有可以的东西 只能通过反思来解决?
我认为,反思主要是语言缺陷的症状。理想情况下,语言应该允许您在不通过反射“弯曲规则”的情况下做您想做的事情。但大多数人不这样做,而C#肯定没有,所以反思偶尔也是你明智的选择。
反射有很多“正确”的用法。动态加载类型/库将是显而易见的。或检查属性。大多数单元测试框架也依赖于反射,这很好,因为它们必须有点干扰,以便易于使用并获得对我们希望测试的代码的访问。
但是大多数用户代码执行某种类型的检查,在运行时测试类型是否实现某个接口或具有某个成员函数,这是一种在理想语言中不应该是必需的东西的标志。
如果你想把它当成气味,可以称它为语言气味,而不是设计气味。 (当然它也可能在设计中被过度使用,但在我经常遇到它的时候,由于缺乏语言的表现力,它是必需的)
答案 2 :(得分:13)
反思有时是做某些事情的唯一方法。它是一个非常强大的工具,有时可能会被那些知道反思的人过度使用,但也许不是别的东西。当其他东西更好地工作时过度使用反射可能是一种设计气味......但更多时候可能只是编码不好。
答案 3 :(得分:12)
曾经有一个处理文件的程序(该描述的通用性)
通过使用反射,你所要做的只是将DLL放入一个文件夹,应用程序会选择它并使用反射来查找实现某个接口的类并检查一些属性。不需要配置文件。只需放手即可,这对于生产系统来说非常方便,因为我们不需要任何停机时间。
与大多数解决方案一样。还有很多其他方法可以达到同样的目的,但反思确实使这很容易。
答案 4 :(得分:7)
我不会说使用反射是一种设计气味。框架的一个有用特性使静态语言更具动态性。现在从实际的角度来看,如果没有它我可以解决我的问题,我会尽量避免反思。
答案 5 :(得分:6)
以我的拙见,反思应该是最后的手段。反射使代码真的难以理解,仅仅通过查看它,因为语言的语义可以用非常奇怪的方式改变。
我认为这是一种气味。也许不是不好的做法,但会引起人们的注意。
答案 6 :(得分:6)
从概念上讲,反射是一种强大的工具,可用作从非代码到代码的网关以及多态工具。
例如......
正确使用它是一种巧妙的工具,可以将代码提升到更高级别的可重用性和灵活性。没错。
这是设计气味的唯一时间,它被用来做传统功能已经涵盖的事情。 (即,您不希望使用Reflection来获取DataRow的值或其他内容。)
答案 7 :(得分:3)
强大的力量带来了巨大的责任,反射是一个非常强大的工具,如果使用得当,非常好,如果使用不当则非常糟糕,诀窍就是知道你何时过度使用它
答案 8 :(得分:3)
与任何其他技术一样,如果你过分关注它,你可能会开始将它应用于错误的问题。
然而,如果没有反思,有些事情是不可能的;任何类型的通用序列化都是一个很好的例子。另一种是任何类型的插件框架,它在编译时不能访问它在运行时可能需要使用的所有类。答案 9 :(得分:3)
Reflection允许您在运行时检查编译器在编译时使用的相同信息。因此,在编译过程中,可以在没有反射的情况下完成反射所能做的任何事情。这并不意味着反射没有用处:你可能不知道在运行之前你想问什么确切的问题。
如果您在编译时知道某些内容,请在类型系统中表达。这将允许您在编译时捕获错误。例如,
string propVal = myObj.SomeProperty;
我们在这里说,我们在编译时肯定知道myObj
有一个名为SomeProperty
的属性,该属性可以分配给string
- 事实上,虽然它在这里不可见,我们还必须指定myObj
的类或接口类型。
string propVal = (string)myObj.GetType()
.GetProperty("SomeProperty")
.GetValue(myObj, null);
我们在这里说myObj
可能具有相同的属性 - 或者它可能没有(在这种情况下,我们将在运行时获得异常)。
第二个,使用反射,看起来很丑,但在C#4.0中看起来几乎完全相同。它通常也会变慢,但这取决于上下文,并且可能不太适用于C#4.0中的动态功能。
但真正的区别仍在于:静态类型版本可以帮助我们在编译过程中发现错误,而不是将此发现推迟到运行时。
因此,如果你想在编译过程中充分利用静态类型系统来捕获bug,那么试着通过类型系统来陈述你的假设,这相当于说:避免反射,除非真正需要。
答案 10 :(得分:2)
有些问题只能通过反思来解决,但我认为只要有可能,它就可以并且可能应该避免。 C#是一种静态且类型安全的语言,因此请利用这一优势。我认为使用反射通常很容易出错。
答案 11 :(得分:2)
在框架中有效地使用了反射,例如插件框架可能会使用Attributes来声明插件类,测试和模拟框架是另一个例子。
但我同意,一般来说,在一个商业应用程序中,大多数时候它会是“代码味道”(并不总是......)
答案 12 :(得分:2)
编程就是建立抽象。反射是构建抽象的一个非常强大的工具。所以不,如果它导致更少的代码更容易理解,我不会说它是一种设计气味。
你们中的许多人已经指出,反思在框架,测试,模拟等方面占有一席之地。在业务线应用程序中如何?
根据我的经验,当您编写某种规模的业务线应用程序时,您不可避免地最终会编写自己的特定于域的框架和库。这就是反思的地方。
答案 13 :(得分:1)
我正处于一个使用(我第一次)反射的项目中。我不得不承认,它看起来不太好。通常我会努力进行非常小的评论,因为他们认为代码应该尽可能地自我评论,但是在这个项目中,我经常添加评论;这既是为了解释下一个可能需要维护代码的开发人员所做的事情,也是为了我自己的利益而“大声思考”。
底线:如果看起来不明显,请添加评论。总是想想那些可能不得不处理你的烂摊子的人。反思可能看起来很混乱,所以请相应评论。
答案 14 :(得分:1)
反射的一个很好的用途是当你想要实现一个加载项架构时。你需要一些方法来指定“这里是一个DLL,加载它并尝试实例化一个类型”。你不知道手前的类型;所有你知道的是,你可以访问一些界面。唯一的方法是使用反射。
我们的应用程序包含大量可在其中运行的模块。我们有一个数据表,列出模块的DLL名称和从中运行的类,而不是硬编码我们需要在选择模块时启动的类列表。这样,当我们需要添加一个新模块时,我们只需要在表中添加一个新条目。启动模块的代码不会更改。
答案 15 :(得分:1)
不,反射不是设计气味。可以说,它可以被称为“语言/平台气味”。
使用反射,因为代码和代码元数据都存储在程序集中。因此,它们总是更新并且同步。您可以对元数据的一般约定进行编码,而不是在常见情况下明确。
对于.NET中的模块化,模块可以自我描述,这是一个很大的好处。
这可能是由于我自己作为程序员的个人发展,但我发现学习反思主张对可交付成果(程序集)的急需关注。当然还有TDD。
答案 16 :(得分:0)
所有反射都让你在运行时观察类型。如果你是一个黑客,我想你可能会用它编写一些Rube Goldberg的装置,但同样可以说很多其他技术。
框架的许多核心功能(如属性)在没有反射的情况下根本不起作用。
答案 17 :(得分:0)
有时它实际上提高了代码的可重用性。作为一个特例,我曾编写过一个程序,用于将csv导入数据库。使用ORM为表创建类,然后反思这些,我能够创建一个只需要注意特殊情况的导入器,并且添加列可能不需要除了将其添加到db表之外的任何其他内容,并且知道它存在于文件中。
但正如其他人所说,这主要是正确使用的问题。
答案 18 :(得分:0)
嗯,显然反射API是因为它们满足了需求,并且存在一些只能通过使用反射来解决的问题。基本上,当需要根据类型信息在代码中做出决策时需要进行反射,类型信息仅在运行时可用,但在编译时不可用。
答案 19 :(得分:0)
这是最臭的气味之一。 “完全关闭”的语言不需要反思。
答案 20 :(得分:0)
任何人都可以看到使用反射的好处,我认为反射可以帮助您实现更好的设计,尤其是OOP设计概念,而无需编写更多代码。
例如,您可以构建依赖于抽象的松散耦合层,并使用反射来控制运行时特定于实例的行为。
最明显的是:广义的UI图层/组件。
ASP.Net MVC和动态数据的灵活性和生产力只是一个例子,你也可以看到GridView。
答案 21 :(得分:0)
点网框架本身没有大量使用反射,这已经赢得了如此多的人气
使用 F#大量使用反射