在基类方法中引用继承类?

Posted

技术标签:

【中文标题】在基类方法中引用继承类?【英文标题】:Reference inheriting class in base class method? 【发布时间】:2021-11-17 22:20:31 【问题描述】:

我正在寻找在(抽象)基类中提供方法的最佳方式,所有继承类都应该能够使用该方法。 此方法需要引用继承类型的字段和属性。 有没有办法提供这样一个不需要我的原型方法:

传递对每个有问题的继承实例的引用 在每个继承类上实现一个方法,它将对自身的引用传递给基类的方法 为实现类编写扩展方法

上述所有工作,但在他们自己的方式似乎有些不方便和不优雅。

下面是一个例子,我实现了上面三个引用继承类的方法:

using System;

namespace Test

    public abstract class BaseClass
    
        public void ReferenceInheriting(object InheritingInstance)
        
            Console.WriteLine("Do things specific to the inheriting class or instance thereof: " + InheritingInstance.GetType().Name);
        
    
    public class Inheriting : BaseClass
    
        public void MakeUseOfBaseClassImplementation()
        
            base.ReferenceInheriting(this);
        
    
    
    public static class Extensions
    
        public static void BeAvailableForAllImplementing(this BaseClass Inh)
        
            Console.WriteLine("Do things specific to the inheriting class or instance thereof: " + Inh.GetType().Name);
        
    
    
    class program
    
        public static void Main(string[] args)
        
            Inheriting inh = new Inheriting();
            Console.WriteLine("Method 1: Calling the inherited method from an inheriting instance, passing a reference to the instance:");
            inh.ReferenceInheriting(inh);
            Console.WriteLine("Method 2: Implementing call to the base class's method in own class:");
            inh.MakeUseOfBaseClassImplementation();
            Console.WriteLine("Method 3: Extension method for all implementing classes:");
            inh.BeAvailableForAllImplementing();
        
    

这三种方法都产生相同的输出,但都有缺点。 缺少解析来电者信息,有没有其他方法可以做到这一点? 当然这没什么大不了的,但我有兴趣让这个方法尽可能地对用户友好,无论是实现继承还是调用。

谢谢!

【问题讨论】:

为什么要在这里使用反射?如果 BaseClass 有合法用途,为什么不声明 getMe 附带说明:如果您遵循正常的命名约定,即使对于示例代码,它也会很有帮助。对于阅读问题或试图回答您的人来说,任何非常规的内容都会分散您的注意力。 @JonSkeet 您具体指的是命名约定的哪些方面?当然,名字可能有点长,但我认为他们描述了我对他们的期望,好吧 @BenPhilipp:reflectInheriting 应该是 ReflectInheritinggetMe 应该是 GetMe,等等。我认为问题不在于长度,而在于大小写。它也让我有点失望。 @ThomasBonini 哦!我看到了 【参考方案1】:

你不需要这些。

这个:

    public void reflectInheriting(object inheritingInstance)
    
        Console.WriteLine("Do things specific to the inheriting class or instance thereof: " + inheritingInstance.GetType().Name);
        FieldInfo fi = inheritingInstance.GetType().GetField("getMe");
        Console.WriteLine(fi.GetValue(inheritingInstance));
    

可以简单地改写为:

    public void reflectInheriting()
    
        Console.WriteLine("Do things specific to the inheriting class or instance thereof: " + this.GetType().Name);
        FieldInfo fi = this.GetType().GetField("getMe");
        Console.WriteLine(fi.GetValue(this));
    

这就是你所需要的。

C# 保存对象的实际底层类型,不管它是如何转换的,所以即使在 BaseClass 内部,this.GetType() 也将是 Inheriting


证明没有任何变化的程序输出:

方法一:从继承的实例调用继承的方法,传递对实例的引用:

做特定于继承类或其实例的事情:继承

在 BaseClass 中使用我


方法二:在自己的类中实现对基类方法的调用:

做特定于继承类或其实例的事情: 继承

在 BaseClass 中使用我


方法3:所有实现类的扩展方法:

做特定于继承类或其实例的事情:继承

在 BaseClass 中使用我

【讨论】:

什么...这是如此基本的行为,我不敢相信我不知道它是如何工作的! ?‍♂️谢谢!【参考方案2】:

您可以使用反射,但这是一种最后的武器。在派生类中访问属性或方法的惯用方式是在基类中将其抽象化。

public abstract class BaseClass

    public void GetInheriting()
    
        Console.WriteLine("GetMe is: 0", this.GetMe);
    

    protected abstract string GetMe  get; 


public class Inheriting : BaseClass

    protected override string GetMe => "Use me in BaseClass"; 
    
    public void MakeUseOfBaseClassImplementation()
    
        base.GetInheriting();
    


public class Program

    static public void Main()
    
        var o = new Inheriting();
        o.MakeUseOfBaseClassImplementation();
    

Link to Fiddle

输出:

GetMe is: Use me in BaseClass

【讨论】:

反射是我首先想要实现的一部分。请注意,我并没有尝试使用反射来获取对该类的引用,并且它不用于尝试回答问题。实际实现为所有继承类提供自定义功能,需要从中获取属性和字段 很公平......当有人提出问题时,很难说他们知道多少,不知道多少,我不想错过“正常”的方法。我相信您有充分的理由使用反射。 很抱歉造成了一些混乱,我想我会让我的部分代码作为使用继承类的示例,但似乎这是一个坏主意?反射现在从我的问题中删除。感谢您的时间和投入,对不起,我在试图说明我的问题时不太清楚^^

以上是关于在基类方法中引用继承类?的主要内容,如果未能解决你的问题,请参考以下文章

C# 隐藏方法和重写方法

在基类对象内部创建派生类对象

C#中基类属性值在子类中设置,如何在基类的方法中获取子类设置的值?

C#中Abstract和Virtual的区别

c++ 在基类类型的向量中调用子类方法

在基类中创建的对象调用方法中的 PHP 类型提示