在C#中是否有任何方法可以使用扩展方法覆盖类方法?

时间:2009-05-22 19:17:18

标签: c# extension-methods override

在某些情况下,我想要使用扩展方法覆盖类中的方法。有没有办法在C#中做到这一点?

例如:

public static class StringExtension
{
    public static int GetHashCode(this string inStr)
    {
        return MyHash(inStr);
    }
}

我想要这样做的一种情况是能够将字符串的散列存储到数据库中,并且所有使用字符串类的散列的类(即字典等)都使用相同的值。 )由于内置的​​.Net哈希算法不能保证从一个版本的Framework到下一个版本兼容,我想用自己的版本替换它。

还有其他情况我遇到了我想用扩展方法覆盖类方法的地方,所以它不仅仅特定于字符串类或GetHashCode方法。

我知道我可以通过子类化现有的类来做到这一点,但是在很多情况下能够使用扩展来做它会很方便。

4 个答案:

答案 0 :(得分:89)

没有;扩展方法永远不会优先于具有合适签名的实例方法,并且永远不会参与多态(GetHashCodevirtual方法)。

答案 1 :(得分:7)

如果该方法具有不同的签名,则可以完成 - 因此在您的情况下:否。

但是否则你需要使用继承来做你想要的。

答案 2 :(得分:2)

据我所知,答案是否定的,因为扩展方法不是一个实例。对我而言,它更像是一个智能感知工具,可以让你使用类的实例调用静态方法。 我认为你的问题的解决方案可以是拦截特定方法(例如GetHashCode())的执行并执行其他操作的拦截器。要使用这样的拦截器(如Castle Project提供的那样),所有对象都应该使用一个实例来实现。对象工厂(或Castle中的IoC容器),以便可以通过在运行时生成的动态代理拦截它们的接口。(Caslte还允许您拦截类的虚拟成员)

答案 3 :(得分:0)

我已经找到了一种调用扩展方法的方法,该方法具有与类方法相同的签名,但是它看起来并不十分优雅。在使用扩展方法时,我注意到一些未记录的行为。示例代码:

public static class TestableExtensions
{
    public static string GetDesc(this ITestable ele)
    {
        return "Extension GetDesc";
    }

    public static void ValDesc(this ITestable ele, string choice)
    {
        if (choice == "ext def")
        {
            Console.WriteLine($"Base.Ext.Ext.GetDesc: {ele.GetDesc()}");
        }
        else if (choice == "ext base" && ele is BaseTest b)
        {
            Console.WriteLine($"Base.Ext.Base.GetDesc: {b.BaseFunc()}");
        }
    }

    public static string ExtFunc(this ITestable ele)
    {
        return ele.GetDesc();
    }

    public static void ExtAction(this ITestable ele, string choice)
    {
        ele.ValDesc(choice);
    }
}

public interface ITestable
{

}

public class BaseTest : ITestable
{
    public string GetDesc()
    {
        return "Base GetDesc";
    }

    public void ValDesc(string choice)
    {
        if (choice == "")
        {
            Console.WriteLine($"Base.GetDesc: {GetDesc()}");
        }
        else if (choice == "ext")
        {
            Console.WriteLine($"Base.Ext.GetDesc: {this.ExtFunc()}");
        }
        else
        {
            this.ExtAction(choice);
        }
    }

    public string BaseFunc()
    {
        return GetDesc();
    }
}

我注意到的是,如果我从扩展方法内部调用了第二个方法,即使存在一个也与签名匹配的类方法,它也会调用与签名匹配的扩展方法。例如,在上面的代码中,当我调用ExtFunc()时,依次调用ele.GetDesc(),我得到的返回字符串为“ Extension GetDesc”,而不是我们期望的字符串“ Base GetDesc”。

测试代码:

var bt = new BaseTest();
bt.ValDesc("");
//Output is Base.GetDesc: Base GetDesc
bt.ValDesc("ext");
//Output is Base.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext def");
//Output is Base.Ext.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext base");
//Output is Base.Ext.Base.GetDesc: Base GetDesc

这允许您随意在类方法和扩展方法之间来回跳动,但需要添加重复的“传递”方法才能进入所需的“作用域”。我称此范围为缺少更好的词。希望有人能让我知道它的真正含义。

您可能已经猜到我的“传递”方法名称,我也很喜欢将委托传递给他们的想法,希望一个或两个方法可以充当具有相同方法的多个方法的传递签名。不幸的是,一旦委托被解压缩,就不会总是选择类方法而不是扩展方法,即使从另一个扩展方法内部也是如此。 “范围”不再重要。我并没有非常多地使用Action和Func代表,所以也许有经验的人可以弄清楚这一点。