C# 重写扩展方法
我一直在考虑使用扩展方法代替抽象基类。扩展方法可以提供默认功能,并且可以通过在派生类中放置具有相同签名的方法来“重写” 有什么理由我不应该这样做吗C# 重写扩展方法,c#,C#,我一直在考虑使用扩展方法代替抽象基类。扩展方法可以提供默认功能,并且可以通过在派生类中放置具有相同签名的方法来“重写” 有什么理由我不应该这样做吗 另外,如果我有两个具有相同签名的扩展方法,那么使用哪一个?有没有建立优先级的方法?一般来说,您不应该通过扩展方法提供“基本”功能。它们只能用于“扩展”类功能。如果您可以访问基类代码,并且您尝试实现的功能在逻辑上是继承继承继承权的一部分,那么您应该将其放在抽象类中 我的观点是,仅仅因为你能,并不意味着你应该。当普通的旧OO编程无法为您提供合理的解决方案
另外,如果我有两个具有相同签名的扩展方法,那么使用哪一个?有没有建立优先级的方法?一般来说,您不应该通过扩展方法提供“基本”功能。它们只能用于“扩展”类功能。如果您可以访问基类代码,并且您尝试实现的功能在逻辑上是继承继承继承权的一部分,那么您应该将其放在抽象类中
我的观点是,仅仅因为你能,并不意味着你应该。当普通的旧OO编程无法为您提供合理的解决方案时,最好还是坚持使用好的老式OOP并使用更新的语言功能。它们是语义不同的操作。例如,多态性可能不会像处理抽象基类那样工作
一般来说,使用任何语言工具都可以达到它的目的。扩展方法不是继承的替代品,它们是一种使用(通常)它已经可见的接口扩展类功能的技术。我同意Michael的观点。基类应该包含所有的基本功能扩展方法,显然,应该扩展基本功能。在Ruby这样的动态语言中,通常使用扩展方法来提供附加功能,而不是使用子类。基本上,扩展方法是使用子类替换,而不是使用基类替换 我看到的唯一例外是,如果您有多个具有不同类层次结构的类型(如winform控件),您可以为每个类型创建一个子类,所有这些类型都实现和接口,然后扩展该接口,从而为一组不同的控件提供“基本”功能,没有扩展控件或对象之类的所有内容 编辑:回答你的第二个问题
我想编译器会帮你捕捉到这个 你完全有理由不这么做。首先,您不能保证如何调用扩展:
MyExtensions.AMethod(myObj)
或
第二个仅仅是第一个的语法糖分
你的建议与语言特色的精神背道而驰。扩展方法显然不是面向对象的。然而,您正试图实现一种面向对象的技术。不要为此使用扩展方法。这绝对是个坏主意。扩展方法是静态绑定的,这意味着,除非对编译时类型为子类型的对象调用重写,否则仍将继续调用扩展方法。再见。对扩展方法的危险进行了很好的讨论。这里的所有答案都说“你不能”,这是事实。大多数人补充说“你不应该”。我想说明的是,你应该能够——尽管这可能是一个小小的安慰 以一个痛苦的现实世界为例:如果您不幸使用了新的MVC框架,并且您的视图代码到处都在使用某种HtmlHelper扩展方法,并且您希望覆盖其默认行为。。。然后呢 你是索尔,就是这样。即使您做了“面向对象的事情”——从HtmlHelper派生,更改基本视图类以将“Html”对象实例替换为派生HtmlHelper的实例,并在其中定义一个显式的“Foo”方法——即使您做了所有这些,调用“Html.Foo”仍将调用原始扩展方法而不是方法 这太令人惊讶了!毕竟,只有当对象还没有方法时,才需要应用扩展方法!这是怎么回事 这是因为扩展方法是静态的。也就是说,当看到“Html.Foo”时,编译器会查看“Html”的静态类型。如果它有一个“Foo”方法,则会像往常一样调用它。否则,如果有“SomeClass”提供“Foo”扩展方法,它会将表达式转换为“SomeClass.Foo(Html)” <>你希望编译器会考虑对象的<强>动态< /强>类型。也就是说,生成的(伪)代码将读取'Html.HasMethod(“Foo”)?Html.Foo():SomeClass.Foo(Html') 这当然会导致在每个扩展方法调用中使用反射的成本。因此,您可以编写类似“staticvoidfoo(virtualthishtmlhelperhtml)”的代码来显式请求编译器插入运行时检查。称之为“虚拟扩展方法”
然而,在他们有限的预算和无限的智慧下,C语言设计师只选择了更高效、更受限的替代方案。当我需要覆盖HtmlHelper的默认行为时,这让我仍然很满意:-(首先,最好将[new]作为方法修饰符进行检查-它应该提供相同的性能和方法分离,但麻烦要小得多
如果你仍然在思考同样的技巧,这里有一些主要的选择要考虑-没有涉及意识形态,只是列出你需要知道的ApCets:-(<)/P> 首先,为了保证确定性函数选择,您可能必须将所有使用限制在模板化函数参数上,因为这种技巧将创建与CLR保证跨函数调用边界的确定性绑定优先级完全相反的情况
如果您仍将拥有抽象基类,并且拥有所有代码,那么只需将一个基类方法“转换”为扩展,您将不会得到任何东西,并且只会损失一个公共接口,该接口将仍然存在于所有其他对象中,包括myObj.AMethod()