重写 LINQ 扩展方法

2024-01-02

有没有一种方法可以覆盖扩展方法(提供更好的实现),而无需显式转换为它们?我正在实现一种数据类型,它能够比默认扩展方法更有效地处理某些操作,但我想保留 IEnumerable 的通用性。这样任何 IEnumerable 都可以传递,但是当我的类传入时,它应该更高效。

作为一个玩具示例,请考虑以下内容:

// Compile: dmcs -out:test.exe test.cs

using System;

namespace Test {
    public interface IBoat {
        void Float ();
    }

    public class NiceBoat : IBoat {
        public void Float () {
            Console.WriteLine ("NiceBoat floating!");
        }
    }

    public class NicerBoat : IBoat {
        public void Float () {
            Console.WriteLine ("NicerBoat floating!");
        }

        public void BlowHorn () {
            Console.WriteLine ("NicerBoat: TOOOOOT!");
        }
    }

    public static class BoatExtensions {
        public static void BlowHorn (this IBoat boat) {
            Console.WriteLine ("Patched on horn for {0}: TWEET", boat.GetType().Name);
        }
    }

    public class TestApp {
        static void Main (string [] args) {
            IBoat niceboat = new NiceBoat ();
            IBoat nicerboat = new NicerBoat ();

            Console.WriteLine ("## Both should float:");
            niceboat.Float ();
            nicerboat.Float ();
            // Output:
            //      NiceBoat floating!
            //      NicerBoat floating!

            Console.WriteLine ();
            Console.WriteLine ("## One has an awesome horn:");
            niceboat.BlowHorn ();
            nicerboat.BlowHorn ();
            // Output:
            //      Patched on horn for NiceBoat: TWEET
            //      Patched on horn for NicerBoat: TWEET

            Console.WriteLine ();
            Console.WriteLine ("## That didn't work, but it does when we cast:");
            (niceboat as NiceBoat).BlowHorn ();
            (nicerboat as NicerBoat).BlowHorn ();
            // Output:
            //      Patched on horn for NiceBoat: TWEET
            //      NicerBoat: TOOOOOT!

            Console.WriteLine ();
            Console.WriteLine ("## Problem is: I don't always know the type of the objects.");
            Console.WriteLine ("## How can I make it use the class objects when the are");
            Console.WriteLine ("## implemented and extension methods when they are not,");
            Console.WriteLine ("## without having to explicitely cast?");
        }
    }
}

有没有一种方法可以从第二种情况中获得行为,而无需显式转换?这个问题可以避免吗?


扩展方法是静态方法,您不能覆盖静态方法。您也不能使用静态/扩展方法“覆盖”实际实例方法。

您必须明确使用优化的扩展。或者通过隐式引用您自己的扩展的命名空间而不是System.Linq.

或者显式检查扩展中的类型并根据运行时类型调用正确的类型。

这似乎是一个比扩展方法更适合继承的问题。如果您需要基于运行时类型的不同功能,则将基方法设为虚拟并在派生类中重写它。

我发现扩展方法在这方面存在很多混乱。你必须明白它们不是 mixin,它们实际上并没有被注入到类中。它们只是编译器识别的语法糖,并“允许”您像常规实例方法一样执行它。想象一下它不是一个扩展方法,只是一个静态方法:

public static void BlowHorn (IBoat boat) {
    Console.WriteLine ("Patched on horn for {0}: TWEET", boat.GetType().Name);
}

您将如何从IBoat执行?你不能。您唯一能做的就是将类型检查放入此静态方法中,或者编写一些动态方法调用代码,或者使用dynamicC# 4 中的块或早期版本中的反射。

为了使这一点更清楚,请查看以下代码System.Linq.Enumerable反射器类:

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, 
    int index)
{
    TSource current;
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
        IList<TSource> list = source as IList<TSource>;
    if (list != null)
    {
        return list[index];
    }
// ...
}

这是.NET Framework 中的核心扩展方法之一。它允许通过显式检查参数是否实现来进行优化IList<T>。除此之外,它无法知道底层具体类型是否实际上支持索引访问。你必须以同样的方式这样做;创建另一个界面,例如IHorn或其他东西,然后在您的扩展中检查是否IBoat还实现了IHorn,与Enumerable类在这里。

如果您不控制任一代码IBoat类或扩展方法,那么你就不走运了。如果这样做,那么使用多接口继承、显式类型检查或动态代码,这些都是您的选择。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重写 LINQ 扩展方法 的相关文章

  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • SSH 主机密钥指纹与模式 C# WinSCP 不匹配

    我尝试通过 WinSCP 使用 C 连接到 FTPS 服务器 但收到此错误 SSH 主机密钥指纹 与模式不匹配 经过大量研究 我相信这与密钥的长度有关 当使用 服务器和协议信息 下的界面进行连接时 我从 WinSCP 获得的密钥是xx xx
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 为什么禁止在 constexpr 函数中使用 goto?

    C 14 对你能做什么和不能做什么有规则constexpr功能 其中一些 没有asm 没有静态变量 看起来相当合理 但标准也不允许goto in constexpr功能 即使它允许其他控制流机制 这种区别背后的原因是什么 我以为我们已经过去
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • 可空属性与可空局部变量

    我对以下行为感到困惑Nullable types class TestClass public int value 0 TestClass test new TestClass Now Nullable GetUnderlyingType
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • 如何在.NET Core上直接调用F#编译器?

    UPD 我想直接从 NET Core SDK 调用 F 编译器 即 fsc 我了解 dotnet build co 但当我只需要编译一个简单的问题时 即 fsc file fs 就足够的情况下 我不想涉及它们 我尝试在 NET Core S
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • GDK3/GTK3窗口更新的精确定时

    我有一个使用 GTK 用 C 语言编写的应用程序 尽管该语言对于这个问题可能并不重要 这个应用程序有全屏gtk window与单个gtk drawing area 对于绘图区域 我已经通过注册了一个刻度回调gtk widget add ti
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz

随机推荐

  • CORS 请求已预检,但似乎不应该

    以下跨源 POST 请求 内容类型为 multipart form data 并且仅预检简单标头 根据 W3C 规范 除非我读错了 否则不应该进行预检 我已经确认 Chrome 27 和 Firefox 10 8 3 中会发生这种情况 我没
  • C++ 命名空间,与 Java 包的比较

    我最近完成了一堆 Java 编码 并且已经习惯了非常具体的包命名系统 例如深度嵌套 com company project db 这在 Java AS3 Flex 和 C 中运行良好 我也看到过 C 中应用了相同的范例 但我也听说将 C 命
  • 有没有使用 firebug 的教程/指南?

    我刚刚获得了 Firefox 的附加组件 到目前为止它非常棒 但我所做的只是在页面上移动光标来获取 css html 我知道还有更多的 Firebug 应用程序 既然 Firebug 如此受欢迎 是否有一个初学者指南 或者只是需要练习的东西
  • 如何查找存储过程中使用的表列表,而无需“With(nolock)”字样[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有很大的表数据 每个表都需要以语句 nolock 结尾 请帮我在所有存储过程中查找 Example 如果存储过程使用两个表 a 和 b 并
  • MySQL Linq 使用 .Contains(变量)

    设置信息 VS2013 C EF6 MySQL数据库 Net 连接器 6 9 5 我正在尝试创建一种方法 该方法使用部分名称作为搜索条件返回帐户记录的集合 如果我使用 IQueryable Contains 扩展方法对字符串值进行硬编码 它
  • 是否可以在 React Native 中使用 React hooks?

    在 React 文档中 它说变量和监听器钩子必须在组件内声明 但当我尝试这样做时 React Native 会抱怨 有没有办法在React Native中使用Hooks 或者有谁知道它们将来是否会实施 不过有点像useEffect不管用 当
  • 使用.NET检查AWS中是否存在SQS

    我能够使用 AWSSDK SQS 包中的 AmazonSQSClient 客户端成功将消息发送到 NET 中的队列 如何检查特定队列是否存在以及是否未创建 您需要使用以下命令运行检查AmazonSQSClient GetQueueUrl s
  • bash 脚本中的 if 条件取反

    我一直试图否定以下命令 wget q tries 10 timeout 20 spider http google com if eq 0 then echo Sorry you are Offline exit 1 如果我连接到互联网 则
  • 如何使用 Spring Boot 和 Spring Security 保护 REST API 的安全?

    我知道保护 REST API 是一个被广泛评论的话题 但我无法创建一个满足我的标准的小型原型 并且我需要确认这些标准是现实的 如何保护资源以及如何使用 Spring 安全性有很多选择 我需要澄清我的需求是否现实 我的要求 基于令牌的身份验证
  • 如何获取写入的记录数(使用DataFrameWriter的保存操作)?

    使用spark保存记录时有没有办法获取写入的记录数 虽然我知道它目前不在规范中 但我希望能够执行以下操作 val count df write csv path 或者 能够对步骤的结果进行内联计数 最好不使用标准累加器 将 几乎 同样有效
  • iOS 10 中 UICollectionView 预取数据源?

    目的是什么prefetchDataSourcesiOS 10 中引入 我刚刚在 XCode 8 GM Seed 中运行一个项目并开始出现错误 MessagesExtension 17902 1238603 Assertion failure
  • 在Python中打印字符串会在字符串之前打印“u”吗?

    打印列表中元素之前的 u 我没有在代码中输入 u hobbies prompt user three times for hobbies for i in range 3 hobby raw input Enter a hobby hobb
  • 使用 IDE 运行 Spring-boot 的 main

    我有一个 spring boot 应用程序需要 可作为 Servlet 容器中的战争进行部署 可通过 mvn spring boot run 运行 我还希望能够通过右键单击 IDE Eclipse 或 IntelliJ IDEA Commu
  • NSFilePresenter 方法永远不会被调用

    我正在尝试编写一个简单的 玩具 程序 它使用 NSFilePresenter 和 NSFileCoordinator 方法来监视文件的更改 该程序由一个加载 硬编码 文本文件的文本视图和一个用于保存文件更改的按钮组成 我的想法是 我有两个实
  • 在 Windows Mobile 应用程序中播放 YouTube 视频

    我正在开发一个用于 Windows Mobile 6 或可能 5 的应用程序 用于播放 YouTube 视频 嗯 它should播放 YouTube 视频 并控制 查询播放器的状态变化 当前帧 时间等 在网上搜索了相当长一段时间 以及一些尝
  • Hibernate 验证器中的自定义消息密钥不适用于 message.property

    我正在研究 Spring Boot 我使用 Hibernate Validator 来验证我的 bean 我添加了一个自定义键 NotEmpty注释 并在 message properties 中添加键 值对 但它没有从 message p
  • Laravel 4:如何向 DB::table 添加范围?

    使用 Eloquent 模型添加范围很容易 public function scopeMyScope query Do stuff to that query 但如何添加范围DB table 我使用此查询来获取页面浏览量 views DB
  • 如何在 Dart 中只替换字符串中的一个字符?

    我试图仅替换字符串 dart 中的一个字符 但找不到任何有效的方法 由于字符串不是 Dart 中的数组 我无法通过索引直接访问字符 并且没有内置函数可以做到这一点 这样做的有效方法是什么 目前我正在这样做 如下所示 List
  • 对话框过渡效果

    I am currently working on the transition effects for my dialog Please refer to the image below 我的对话框的入口动画应该是从上到中 而退出动画应该
  • 重写 LINQ 扩展方法

    有没有一种方法可以覆盖扩展方法 提供更好的实现 而无需显式转换为它们 我正在实现一种数据类型 它能够比默认扩展方法更有效地处理某些操作 但我想保留 IEnumerable 的通用性 这样任何 IEnumerable 都可以传递 但是当我的类