Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 重写扩展方法_C# - Fatal编程技术网

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()