繁体   English   中英

覆盖LINQ扩展方法

[英]Overriding LINQ extension methods

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

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

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

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

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

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

为了使这更清楚,请查看Reflector中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类或扩展方法的代码,那么您运气不好。 如果这样做,那么使用多接口继承,显式类型检查或动态代码,这些都是您的选择。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM