C# 有没有办法用扩展方法覆盖类方法?

发布于 2024-07-21 18:17:52 字数 456 浏览 4 评论 0原文

有时我想用扩展方法重写类中的方法。 在 C# 中有什么办法可以做到这一点吗?

例如:

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

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

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

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

There have been occasions where I would want to override a method in a class with an extension method. Is there any way to do that in C#?

For example:

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

A case where I've wanted to do this is to be able to store a hash of a string into a database and have that same value be used by all the classes that use the string class's hash (i.e. Dictionary, etc.) Since the built-in .NET hashing algorithm is not guaranteed to be compatible from one version of the framework to the next, I want to replace it with my own.

There are other cases I've run into where I'd want to override a class method with an extension method as well so it's not just specific to the string class or the GetHashCode method.

I know I could do this with subclassing off an existing class but it would be handy to be able to do it with an extension in a lot of cases.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

前事休说 2024-07-28 18:17:52

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

但否则您需要使用继承来完成您想要的操作。

If the method has a different signature, then it can be done -- so in your case: no.

But otherwise you need to use inheritance to do what you are looking for.

归属感 2024-07-28 18:17:52

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

No; an extension method never takes priority over an instance method with a suitable signature, and never participates in polymorphism (GetHashCode is a virtual method).

ゝ偶尔ゞ 2024-07-28 18:17:52

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

As far as I know the answer is no, because an extension method is not an instance.It's more like an intellisense facility to me that let you call a static method using an instance of a class.
I think a solution to your problem can be an interceptor that intercepts the execution of a specific method (e.g. GetHashCode()) and do something else.To use such an interceptor (like the one Castle Project provides) all objects should be instansiated using an object factory (or an IoC container in Castle) so that thier interfaces can be intercepted through a dynamic proxy generated in runtime.(Caslte also lets you intercept virtual members of classes)

Spring初心 2024-07-28 18:17:52

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

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(),而 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 代表,所以也许更有经验的人可以弄清楚这部分。

I have found a way to invoke an extension method with the same signature as a class method, however it does not seem very elegant. When playing around with extension methods I noticed some undocumented behavior. Sample code:

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();
    }
}

What I noticed was that if I called a second method from inside an extension method, it would call the extension method that matched the signature even if there was a class method that also matched the signature. For example in the code above, when I call ExtFunc(), which in turn calls ele.GetDesc(), I get the return string "Extension GetDesc" instead of the string "Base GetDesc" that we would expect.

Testing the code:

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

This allows you to bounce back and forth between class methods and extension methods at will, but requires the addition of duplicate "pass-through" methods to get you into the "scope" you desire. I am calling it scope here for lack of a better word. Hopefully someone can let me know what it is actually called.

You might have guessed by my "pass-through" method names that I also toyed with the idea of passing delegates to them in the hopes that a single method or two could act as a pass-through for multiple methods with the same signature. Unfortunately it was not to be as once the delegate was unpacked it always chose the class method over the extension method even from inside another extension method. "Scope" no longer mattered. I have not used Action and Func delegates very much though so maybe someone more experienced could figure that part out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文