107

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

例如:

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

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

在其他情况下,我还想用扩展方法覆盖类方法,因此它不仅仅特定于字符串类或GetHashCode方法。

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

4

4 回答 4

98

不; 扩展方法永远不会优先于具有合适签名的实例方法,并且永远不会参与多态性(GetHashCode是一种virtual方法)。

于 2009-05-22T19:20:20.293 回答
8

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

但否则你需要使用继承来做你正在寻找的东西。

于 2009-05-22T19:20:46.347 回答
2

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

于 2009-05-23T10:45:07.487 回答
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 代表,所以也许更有经验的人可以弄清楚这部分。

于 2019-03-23T04:52:45.833 回答