C#:繼承過程中的靜態成員


在知乎上看到一個關於“泛基“的實現,感覺挺有意思,想試試效果,代碼如下:

    public abstract class MyBase<T> where T : MyBase<T>
    {
        public static string DataForThisType { get; set; }
        public static T Instance { get; protected set; }
        public static readonly IReadOnlyDictionary<string, MemberInfo> Members = typeof(T).GetMembers().ToDictionary(x => x.Name);
    }

    public class MyClass : MyBase<MyClass>
    {
        static MyClass()
        {
            DataForThisType = string.Format("MyClass got {0} members", Members.Count);
            Instance = new MyClass();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write(MyClass.DataForThisType);
            Console.WriteLine();
            Console.ReadLine();
        }
    }

先忽略這段代碼的作用,重點是運行后控制台沒有任何輸出。跟蹤一下發現根本沒有走MyClass(),DataForThisType的值一直是null。關於靜態構造方法,網上的解釋是:

    • 通常情況下:最先調用基類的構造方法,但如果該類有靜態構造方法,且首次調用該類,則先調用該類的靜態構造方法,再調用其基類的靜態構造方法。
      Child.Static->Super.Static->Super.Instance->Child Instance
    • 靜態構造方法是.net調用的,在創建第一個實例或者靜態成員被引用時,.net將自動調用靜態構造方法來初始化類。

這就有問題了,MyClass的靜態構造方法不僅沒被優先調用,甚至全程都沒有被調用。難道上述這個說法是錯的?為了排除干擾,給上述代碼簡化一下

 

    class Program
    {
        static void Main(string[] args)
        {
            Console.Write(TestChild.StaticPropertyBase);
            Console.WriteLine();
            Console.ReadLine();
        }
    }

    public class TestBase
    {
        public static string StaticPropertyBase { get; protected set; }
    }

    public class TestChild : TestBase
    {
        static TestChild()
        {
            StaticPropertyBase = typeof(TestChild) + ":" + "StaticPropertyBase";      
        }
    }

 

運行結果還是一樣,沒有輸出,TestChild的靜態構造沒被執行。回頭再來看靜態構造方法的調用條件:在創建第一個實例或者靜態成員被引用時!!!實例是肯定沒有的,但

是我有引用靜態成員啊..等等,我引用的好像是父類的靜態成員,難道父類的靜態成員不行?說好的繼承全部家產呢?那就再來試試,給TestChild聲明一個自己的靜態屬性。

   class Program
    {
        static void Main(string[] args)
        {
            Console.Write(TestChild.StaticPropertyChild);
            Console.WriteLine();
            Console.Write(TestChild.StaticPropertyBase);
            Console.WriteLine();
            Console.Write(TestBase.StaticPropertyBase);
            Console.WriteLine();
            Console.ReadLine();
        }
    }

    public class TestBase
    {
        public static string StaticPropertyBase { get; protected set; }
    }

    public class TestChild : TestBase
    {
        public static string StaticPropertyChild { get; set; }
        static TestChild()
        {
            StaticPropertyBase = typeof(TestChild) + ":" + "StaticPropertyBase";
            StaticPropertyChild = "StaticPropertyChild";           
        }
    }

輸出如下:

目前為止可以得出兩個結論:

1)想觸發一個類的靜態構造方法?要么實例化它,要么訪問它的靜態成員,訪問它基類的的靜態成員是不行的。

2)靜態成員的繼承其實並不是真正的繼承,或者說根本就無法繼承,只是訪問父類的靜態成員而已。但與實例成員不同的是,用protected修飾的靜態成員

     可以在其派生類中訪問,用protected修飾的非靜態成員,則不可訪問。下面代碼體會一下,new TestBase().hh =" ";這句報錯。

     報錯的原因描述有誤:實則是因為在一個實例中訪問了另一個實例的protected成員,與是否是基類的實例無關

 public class TestBase
    {

        public static string StaticPropertyBase { get; protected set; }
        public  string hh { get; protected set; }
    }

    public class TestChild : TestBase
    {
        public static string StaticPropertyChild { get; set; }

        static TestChild()
        {
            StaticPropertyBase = typeof(TestChild) + ":" + "StaticPropertyBase";
            StaticPropertyChild = "StaticPropertyChild";           
        }
        TestChild()
        {
            hh = "";
            new TestBase().hh = "";
        }
    }

以上、歡迎交流指正。如有侵權,請聯系作者刪除。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM