一、base关键字
可以通过base关键字访问上一级父类方法的访问。静态static函数无法调用base
二、new 关键字new
new有2个作用。
new运算符 用来分配内存空间和初始化对象。
new修饰符 微软官方说明:可以显式隐藏从基类继承的成员,该成员的派生版本将替换基类版本。(以前一直不在乎这种场合,因为编译器就提示警告)他和overrider有什么区别呢?
/// <summary> /// 关键字 /// </summary> public class KeywordA { public KeywordA() { Name = "apple"; } public string Name { get; set; } public virtual void Test() { Console.WriteLine("KeywordA.Test()" + Name); } public void Test1() { Console.WriteLine("KeywordA.Test1()" + Name); } } public class KeywordB : KeywordA { public KeywordB() { Name = "button"; } public new string Name { get; set; } public new void Test() { Console.WriteLine("KeywordB.Test()" + Name); base.Test(); } public new void Test1() { Console.WriteLine("KeywordB.Test1()" + Name); base.Test1(); } } public class KeywordC : KeywordA { public KeywordC() { Name = "city"; } public override void Test() { Console.WriteLine("KeywordC.Test()"+Name); base.Test(); } }
static void Main(string[] args) { KeywordA a = new KeywordA(); a.Test(); a.Test1(); Console.WriteLine("========================="); KeywordB b = new KeywordB(); b.Test(); b.Test1(); a = new KeywordB(); a.Test(); a.Test1(); Console.WriteLine("========================="); KeywordC c = new KeywordC(); c.Test(); a = new KeywordC(); a.Test(); a.Test1(); Console.WriteLine("========================="); Console.ReadKey(); }
通过以上代码执行得出以下结果:
KeywordA.Test()apple
KeywordA.Test1()apple
=========================
KeywordB.Test()button
KeywordA.Test()apple
KeywordB.Test1()button
KeywordA.Test1()apple
KeywordA.Test()apple
KeywordA.Test1()apple
=========================
KeywordC.Test()city
KeywordA.Test()city
KeywordC.Test()city
KeywordA.Test()city
KeywordA.Test1()city
=========================
1.new 只是个修饰符,看IL代码和不加NEW的方法一样。都叫覆盖。为了减少warn,建议加把。
2.虚方法、实方法都可以被覆盖(new),抽象方法,接口 不可以。
3.不管是重写还是覆盖都不会影响父类自身的功能。
4.当用子类创建父类的时候,如 A c = new B(),重写会调用子类的功能;而覆盖不会,仍然调用父类功能。
三、abstract 修饰符 abstract关键字
关于virtual 虚方法和抽象方法 、抽象类网上资料太多了。也非常好区分。abstract继承类必须实现抽象定义。而virtual 可以选择是否重写基类虚方法。 这里就摘录微软的定义了:
- abstract 修饰符指示所修饰的内容缺少实现或未完全实现。
- abstract 修饰符可用于类、方法、属性、索引器和事件。
- 标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
抽象类具有以下特性:
- 抽象类不能实例化。
- 抽象类可以包含抽象方法和抽象访问器。
- 不能用 sealed(C# 参考) 修饰符修饰抽象类,因为这两个修饰符的含义是相反的。 采用 sealed 修饰符的类无法继承,而 abstract 修饰符要求对类进行继承。
- 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实际实现。
四、virtual 修饰符
virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。
除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。
- 在静态属性上使用 virtual 修饰符是错误的。
- 通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。
五、const / readonly
都是只读的意思。表面上看区别在于const首次赋值后就不可以改了,而readonly在初始化类后就不能修改了。
public class Keyword2 { public static string Name_static = "Name_static"; public readonly string Name_readonly = "Name_readonly"; public const string Name_const = "Name_const"; public static readonly string Name_static_readonly = "Name_static_readonly"; public Keyword2(string text="Init") { Name_static = "Name_static_" + text; Name_readonly = "Name_readonly_" + text; //Name_const = "Name_const" + text; //Name_static_readonly = "Name_static_readonly" + text; } }
static void Main(string[] args) { //DoKeyword1(); DoKeyword2(); Console.ReadKey(); } /// <summary> /// const readonly /// </summary> private static void DoKeyword2() { Console.WriteLine("========初始化字段================="); Console.WriteLine(Keyword2.Name_const); Console.WriteLine(Keyword2.Name_static); Console.WriteLine(Keyword2.Name_static_readonly); Console.WriteLine("========初始化构造函数================="); Keyword2 kw = new Keyword2(); Console.WriteLine(kw.Name_readonly); Console.WriteLine(Keyword2.Name_const); Console.WriteLine(Keyword2.Name_static); Console.WriteLine(Keyword2.Name_static_readonly); Console.WriteLine("========修改内容================="); //Keyword2.Name_const = Keyword2.Name_const+"_Edit"; //Keyword2.Name_static_readonly = Keyword2.Name_static_readonly + "_Edit"; //kw.Name_readonly = Keyword2.Name_readonly + "_Edit"; Keyword2.Name_static = Keyword2.Name_static + "_Edit"; Console.WriteLine(Keyword2.Name_static); }
IL代码:
.class public auto ansi beforefieldinit 关键字使用和执行顺序.Keyword2 extends [mscorlib]System.Object { // Fields .field public static literal string Name_const = "Name_const" .field public static string Name_static .field public initonly string Name_readonly .field public static initonly string Name_static_readonly // Methods .method public hidebysig specialname rtspecialname instance void .ctor ( [opt] string text ) cil managed { .param [1] = "Init" // Method begins at RVA 0x2156 // Code size 54 (0x36) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldstr "Name_readonly" IL_0006: stfld string 关键字使用和执行顺序.Keyword2::Name_readonly IL_000b: ldarg.0 IL_000c: call instance void [mscorlib]System.Object::.ctor() IL_0011: nop IL_0012: nop IL_0013: ldstr "Name_static_" IL_0018: ldarg.1 IL_0019: call string [mscorlib]System.String::Concat(string, string) IL_001e: stsfld string 关键字使用和执行顺序.Keyword2::Name_static IL_0023: ldarg.0 IL_0024: ldstr "Name_readonly_" IL_0029: ldarg.1 IL_002a: call string [mscorlib]System.String::Concat(string, string) IL_002f: stfld string 关键字使用和执行顺序.Keyword2::Name_readonly IL_0034: nop IL_0035: ret } // end of method Keyword2::.ctor .method private hidebysig specialname rtspecialname static void .cctor () cil managed { // Method begins at RVA 0x218d // Code size 21 (0x15) .maxstack 8 IL_0000: ldstr "Name_static" IL_0005: stsfld string 关键字使用和执行顺序.Keyword2::Name_static IL_000a: ldstr "Name_static_readonly" IL_000f: stsfld string 关键字使用和执行顺序.Keyword2::Name_static_readonly IL_0014: ret } // end of method Keyword2::.cctor } // end of class 关键字使用和执行顺序.Keyword2
总结:
1.const 为啥不需要实例化知道了把。它也是静态的。
2.Name_readonly 在编译时自动将赋值写入构造函数,完成初始化值的。所以readonly的在构造函数内可修改。
3.初始化顺序是 先 const-> static ->构造函数。
六、volatile 修饰符
七、in/out 泛型修饰符
八、async 异步修饰符