在知乎上看到一个关于“泛基“的实现,感觉挺有意思,想试试效果,代码如下:
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 = "";}}
以上、欢迎交流指正。如有侵权,请联系作者删除。