如何在调用基类的静态函数之前设置派生静态成员

Posted

技术标签:

【中文标题】如何在调用基类的静态函数之前设置派生静态成员【英文标题】:How can I set derived static members before calling static functions of the base class 【发布时间】:2016-12-21 13:25:17 【问题描述】:

我有以下课程:

class Base<T> where T : Base<T>

    protected static string Source;

    public static List<T> Read()
    
        return GetResource(Source);
    

我希望这个类作为其功能的基类,但每个派生类都必须有不同的来源。我的问题是我无法确保在调用 Read 之前设置了 Source。我知道我可以询问是否在调用 GetResource 之前设置了 Source,但这不是重点。我需要在调用我的类的任何静态成员之前设置它。

泛型参数不能有静态成员,所以我不能从那里获取它。

我尝试在派生类的静态构造函数中设置 Source,但只有当我调用派生类中的成员而不是基类中的成员时才会调用它。

我尝试在静态 Base 构造函数中使用可覆盖的方法,但这样的方法也必须是静态的,并且不能覆盖静态方法。

当我手动设置 Source 时,可能已经调用了 Read-Function,所以我必须设置 Source 在它被调用之前。

我知道我可以在 Read 中将 Source 作为参数,但我希望 Read 不带参数使用。

有什么方法可以确保在调用我的类的任何其他成员之前设置源,以便任何依赖代码在派生类内部并且不必调用任何人使用派生类?

我基本上希望它像这样工作:

class Derived : Base<Derived>

    // somehow set Source
    Source = "This is my source";


class User

    private List<Derived> MyResources;

    public User()
    
        MyResources = Derived.Read();
    
 

注意:Source 基本上是一条 SQL 语句,所以我认为 Attribute 或类似的东西是不够的。

【问题讨论】:

派生类可以有一个构造函数来初始化属性。 我知道,我对它进行了测试,但是每当我调用任何基本成员时,都不会调用派生构造函数。只有当我调用非派生成员时才会调用它。未在 Base 中声明的一种。 我不确定是否有更好的方法,但您可以Base 的静态构造函数通过反射查找派生类型,并强制它们的构造函数为称为 (RuntimeHelpers.RunClassConstructor)... 但这似乎相当 hacky(并且它可能会导致其他程序集中的派生类出现问题)。如果我是你,我不会在这里使用静态方法。 我希望我可以避免它,但由于这些静态方法就像一个工厂,我真的别无选择,只能使用静态方法。我找到了一种方法来做到这一点,尽管我希望找到另一种方法,但现在已经足够了。 你真的需要方法和字段是静态的吗?你这样做有什么收获?如果没有这个限制,子类可以定义需要 source 作为参数的构造函数,这是必需初始化的常见模式。 【参考方案1】:

好的,我找到了答案。它不像我希望的那样漂亮,但它是我能想到的最好的。

我将使用接口来强制 T 的实例具有提供我的源的特定方法。

interface ISource

    string GetSource();

然后我将它实现到我的基类中:

class Base<T> where T : Base<T>, ISource, new()

    public static List<T> Read()
    
        // here I create an Instance to be able to call the Methods of T
        string source = (new T()).GetSource();
        return GetResource(source);
    

派生类:

class Derived : Base<Derived>, ISource

    public string GetSource()
    
        return "This specific source";
    

这样的用法:

class User

    public User()
    
        List<Derived> myResources = Derived.Read();
    

这当然会导致 Derived 的每个实例都具有 GetSource 方法,但对于我的场景而言,这没什么大不了的。 此外,由于它在 Read 方法中创建一个实例,这可能会很耗时,具体取决于 Derived 的构造函数。在我的场景中,它只有标准构造函数。

因此请谨慎使用。

【讨论】:

以上是关于如何在调用基类的静态函数之前设置派生静态成员的主要内容,如果未能解决你的问题,请参考以下文章

4月14日继承与多态

C++派生类是不是可以从基类继承静态数据成员和静态成员函数?

从基类到派生类的静态转换后找不到成员函数

基类与派生类的指针和成员函数调用原理

C++进阶:继承C++为什么要引入继承 | 继承概念及定义 | 基类和派生类对象赋值转换 | 继承中的作用域 | 派生类的默认成员函数 | 继承与友元/静态成员 | 复杂的菱形继承及菱形虚拟继承

C++进阶:继承C++为什么要引入继承 | 继承概念及定义 | 基类和派生类对象赋值转换 | 继承中的作用域 | 派生类的默认成员函数 | 继承与友元/静态成员 | 复杂的菱形继承及菱形虚拟继承