gpt4 book ai didi

c# - 覆盖 LINQ 扩展方法

转载 作者:太空狗 更新时间:2023-10-29 22:13:07 25 4
gpt4 key购买 nike

有没有一种方法可以覆盖扩展方法(提供更好的实现),而无需显式强制转换它们?我正在实现一种能够比默认扩展方法更有效地处理某些操作的数据类型,但我想保持 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 .

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

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

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

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

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

为了使这一点更清楚,请查看 System.Linq.Enumerable 中的这段代码Reflector 类:

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 的代码类或扩展方法,那么你就不走运了。如果这样做,则使用多接口(interface)继承、显式类型检查或动态代码,这些都是您的选择。

关于c# - 覆盖 LINQ 扩展方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2705864/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com