C#的访问修饰符,声明修饰符,关键字有哪些?扫盲篇

版权声明:本文为博主原创文章,未经博主允许不得转载。QQ527592435 https://blog.csdn.net/cplvfx/article/details/85677995

更多请看

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/modifiers

一、访问修饰符

tip:是添加到类、结构或成员声明的关键字

[1] Public:公有的,是类型和类型成员的访问修饰符。对其访问没有限制。

[2] Internal:内部的,是类型和类型成员的访问修饰符。同一个程序集中的所有类都可以访问

[3] Private:私有的,是一个成员访问修饰符。只有在声明它们的类和结构中才可以访问。

[4] Protected:受保护的,是一个成员访问修饰符。只能在它的类和它的派生类中访问。

[5] protected internal:访问级别为 internal 或 protected。即,“同一个程序集中的所有类,以及所有程序集中的子类都可以访问。

注意点:

一个成员或类型只能有一个访问修饰符,使用 protected internal组合时除外。

扫描二维码关注公众号,回复: 4774744 查看本文章

如果在成员声明中未指定访问修饰符,则使用默认的可访问性

类型成员默认的可访问性

属于

默认的成员可访问性

该成员允许的声明的可访问性

enum

public

class

private

public

protected

internal

private

protected internal

interface

public

struct

private

public

internal

private

Internal 和 protected internal 详解(即什么是同一个程序集)

示例1:(这里同一个程序集指同一个命名空间)

using System;
using System.Collections.Generic;
using System.Text;
namespace Example05Lib
{    
    public class Class1 
     {       
        internal String strInternal = null;       
        public String strPublic;       
        internal protected String strInternalProtected = null;   
    }
}

using System;
using System.Collections.Generic;
using System.text;
namespace Example05Lib
{
    class Class2
    {
        private String tmpStr=new Class1().strInternal;
        private String tmpStr=new Class1().strInternalProtected;
        private String tmpStr=new Class1().strPublic;
     }
}

1.1结果: Class2 类可以访问到 Class1 的 strInternal 成员,当然也可以访问到 strInternalProtected 成员,因为他们在同一个程序集里

using System;
using System.Collections.Generic;
using System.text
using Example05Lib
namespace Example05 
{
    class Program
    {
        class Class3:Class1
        {
            public Class3()
            {
                base.StrInternalProtected;
                base.strPublic;
            } 
        }
    }
 }

1.2结果:Class3 类无法访问到 Class1 的 strInternal 成员,因为它们不在同一个程序集里。但却可以访问到 strInternalProtected 成员,因为 Class3 是 Class1 的继承类。

using System;
using System.Collections.Generic;
using System.text
using Example05Lib
namespace Example05 
{
class Program
{
   static void Main(string[] args)
   {
      String tmpStr=new Class1().strPublic; 
   }
}
}

1.3结果:无法访问到 strInternalProtected 与strInternal 成员,因为它们既不在同一个程序集里也不存在继承关系

示例2(在这里同一个程序集是指同一个.cs文件,不同的.cs文件的命名空间省略)

 2.1该示例包含两个文件:Assembly1.cs 和 Assembly2.cs。第一个文件包含内部基类 BaseClass。在第二个文件中,实例化 BaseClass 的尝试将产生错误。

internal class BaseClass

{

   public static int intM = 0;

}

class TestAccess

{

   static void Main()

   {

      BaseClass myBase = new BaseClass();   // CS0122

   }

}

2.2 使用与示例 1 中所用的文件相同的文件,并将 BaseClass 的可访问性级别更改为 public。还将成员 IntM 的可访问性级别更改为 internal。在此例中,您可以实例化类,但不能访问内部成员。

public class BaseClass

{

   internal static int intM = 0;

}

public class TestAccess

{

   static void Main()

   {

      BaseClass myBase = new BaseClass();   // Ok.

      BaseClass.intM = 444;    // CS0117

   }

}

示例3

对于一些大型的项目,通常由很多个DLL文件组成,引用了这些DLL,就能访问DLL里面的类和类里面的方法。比如,你写了一个记录日志的DLL,任何项目只要引用此DLL就能实现记录日志的功能,这个DLL文件的程序就是一个程序集。

如果你记录日志的程序集是这么定义的

namespace LogerHelper

{

    internal class aa

    {

         public void bb()

         {

             return "";

         }

    }

 

    public class Write

    {

        public void WriteIn(string content)

        {

            class x = new aa();   

            x.bb();

        }

    }

}

当另一个项目引用了此DLL

它可以这么访问 

LogerHelper.Write x = new LogerHelper.Write();

x.WriteIn("");

但不可以这么访问

LogerHelper.aa x = new LogerHelper.aa();

x.bb();

这就叫,只能在程序集中访问

二、声明修饰符

[1] Partial:在整个同一程序集中定义分部类和结构。

[2] Static: 声明属于类型本身而不是属于特定对象的成员。

[3] Abstract:抽象类,只能是其他类的基类。类中的方法只声明不实现,方法的实现在他的派生类中完成。

[4] Sealed:指定类不能被继承。

[5] Virtual:用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象

[6.1] override重写,是在子类中重写父类中的方法,两个函数的函数特征(函数名、参数类型与个数)相同。用于扩展或修改继承的方法、属性、索引器或事件的抽象或虚拟实现。提供从基类继承的成员的新实现,而通过override声明重写的方法称为基方法。

[6.2] overload重载,在同一个类中方法名相同、参数或返回值不同的多个方法即为方法重载。

[6.3] overwrite覆写,用new实现。在子类中用 new 关键字修饰定义的与父类中同名的方法,也称为覆盖,覆盖不会改变父类方法的功能。

[7] New:作修饰符,隐藏从基类成员继承的成员,在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。作运算符,用于创建对象和调用构造函数。

[8] Extern:用于声明在外部实现的方法。 extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 特性一起使用。 在这种情况下,还必须将方法声明为 static

[9]Readonly:修饰字段,表示该字段为只读字段。readonly是运行时只读,内容在运行时确定,所以修改了readonly类型成员后无需重新编译即可生效,Readonly不能修饰局部变量

[10]Const:修饰字段,表示该字段为只读字段。const修饰的字段在编译时必须能够明确知道该字段的值,其值是硬编码到程序中去的,修改了该类型成员后需要重新编译才能使修改生效,const可以修饰局部变量

1.Partial

(它只修饰类),部分的,可以将一个类分成几部分写在不同文件中,最终编译时将合并成一个文件,且各个部分不能分散在不同程序集中

2.Static

(可以修饰类也可以修饰成员)静态的,修饰类时表示该类是静态类,不能实例化该类的对象,既然不能实例化该类,那么这个类也就不能含有对象成员,即该类所有成员为静态;类成员只能通过【类.成员名】的方式访问。当static修饰构造函数时,构造函数不能含有任何参数,不能含有修饰符,构造函数不能对对象成员进行初始化操作。但是能够对静态成员进行初始化或者调用。不能保证他在什么时候执行,却能保证在第一次使用类型前执行。在静态构造函数中初始化的静态成员为最终初始化结果

3.Abstract

(可以修饰类也可以修饰成员)抽象的,修饰类的时候表示该类为抽象类,不能够创建该类的实例。修饰方法的时候表示该方法需要由子类来实现,如果子类没有实现该方法那么子类同样是抽象类;且含有抽象方法的类一定是抽象类

4.Sealed

(可以修饰类也可以修饰成员)密封的,修饰类时表示该类不能够被继承,修饰方法时表示该方法不能被重写【sealed相当于java中的final修饰符】

5.Virtual

修饰方法成员,表示虚方法。父类可以含有该类的实现,子类可以覆写该函数。

6.overload,override,overwrite

重载(过载)overload、重写(覆盖)override、覆写overwrite(new)详解

一、override重写,是在子类中重写父类中的方法,两个函数的函数特征(函数名、参数类型与个数)相同。用于扩展或修改继承的方法、属性、索引器或事件的抽象或虚拟实现。提供从基类继承的成员的新实现,而通过override声明重写的方法称为基方法。 
注意事项: 
1.重写基方法必须具有与override方法相同的签名。 
2.override声明不能更改virtual方法的可访问性,且override方法与virtual方法必须具有相同级别访问修饰符。 
3.不能用new、static、virtual修饰符修改override方法。 
4.重写属性声明必须指定与继承的属性完全相同的访问修饰符、类型和名称。 
5.重写的属性必须是virtual、abstract或override。 
6.不能重写非虚方法或静态方法。 
7.父类中有abstract,那么子类同名方法必定有override,若父类中有 virtual方法,子类同名方法不一定是override,可能是overload。 
8.override必定有父子类关系。

二、overload重载,在同一个类中方法名相同、参数或返回值不同的多个方法即为方法重载。 
注意事项: 
1.出现在同一个类中。 
2.参数列表不同或返回类型和参数列表都不同,只有返回类型不同不能重载。(参数列表包括参数个数和参数类型)

三、overwrite覆写,用new实现。在子类中用 new 关键字修饰定义的与父类中同名的方法,也称为覆盖,覆盖不会改变父类方法的功能。

另一种解释new是指“隐藏”,是指子类隐藏了父类的方法,当然,通过一定的转换,可以在子类的对象中访问父类的方法。

示例:

class Parent
{
    public void F()
    {
        Console.WriteLine("Parent.F()");
    }
    public virtual void G() //抽象方法
    {
        Console.WriteLine("Parent.G()");
    }
    public int Add(int x, int y)
    {
        return x + y;
    }
    public float Add(float x, float y) //重载(overload)Add函数
    {
        return x + y;
    }
}
class ChildOne:Parent //子类一继承父类
{
    new public void F() //重写(overwrite)父类函数
    {
        Console.WriteLine("ChildOne.F()"); 
    }
    public override void G() //覆写(override)父类虚函数,主要实现多态
    {
        Console.WriteLine("ChildOne.G()");
    }
}
class ChildTwo:Parent //子类二继承父类
{
    new public void F()
    {
        Console.WriteLine("ChildTwo.F()");
    }
    public override void G()
    {
        Console.WriteLine("ChildTwo.G()");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Parent childOne = new ChildOne();
        Parent childTwo = new ChildTwo();
        //调用Parent.F()
        childOne.F();
        childTwo.F();
        //实现多态
        childOne.G();
        childTwo.G();
        Parent load = new Parent();
        //重载(overload)
        Console.WriteLine(load.Add(1, 2));
        Console.WriteLine(load.Add(3.4f, 4.5f));
        Console.Read();
    }
}

7.New 关键字的3种用法

三种用法如下:

在 C# 中,new 关键字可用作运算符、修饰符或约束。

1)new 运算符:用于创建对象和调用构造函数。这种大家都比较熟悉,没什么好说的了。

2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。

3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型。 

关于第二种用法看下例:

作修饰符,隐藏从基类成员继承的成员,在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。作运算符,用于创建对象和调用构造函数。

using System;
namespace ConsoleApplication1
{
    public class BaseA
    {
        public int x = 1;
        public void Invoke()
        {
            Console.WriteLine(x.ToString());
        }
        public int TrueValue
        {
            get { return x; }
            set { x = value; }
        }
    }
    public class DerivedB : BaseA
    {
        new public int x = 2;
        new public void Invoke()
        {
            Console.WriteLine(x.ToString());
        }
        new public int TrueValue
        {
            get { return x; }
            set { x = value; }
        }
    }
 
    class Test
    {
        static void Main(string[] args)
        {
            DerivedB b = new DerivedB();
            b.Invoke();//调用DerivedB的Invoke方法,输出:2
            Console.WriteLine(b.x.ToString());//输出DerivedB的成员x值:2
            BaseA a = b;
            a.Invoke();//调用BaseA的Invoke方法,输出:1
            a.TrueValue = 3;//调用BaseA的属性TrueValue,修改BaseA的成员x的值
            Console.WriteLine(a.x.ToString());//输出BaseA的成员x的值:3
            Console.WriteLine(b.TrueValue.ToString());//输出DerivedB的成员x的值,仍然是:1
//可见,要想访问被隐藏的基类的成员变量、属性或方法,办法就是将子类造型为父类,然
//后通过基类访问被隐藏的成员变量、属性或方法。
        }
     }
}
 
new约束指定泛型类声明中的任何类型参数都必须具有公共的无参数构造函数.请看下例:
using System;
using System.Collections.Generic;
 
namespace ConsoleApplication2
{
    public class Employee
    {
        private string name;
        private int id;
 
        public Employee()
        {
            name = "Temp";
            id = 0;
        }
 
        public Employee(string s, int i)
        {
            name = s;
            id = i;
        }
 
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
 
        public int ID
        {
            get { return id; }
            set { id = value; }
        }
    }
 
    class ItemFactory<T> where T : new()
    {
        public T GetNewItem()
        {
            return new T();
        }
    }
 
    public class Test
    {
        public static void Main()
        {
            ItemFactory<Employee> EmployeeFactory = new ItemFactory<Employee>();
            ////此处编译器会检查Employee是否具有公有的无参构造函数。
            //若没有则会有The Employee must have a public parameterless constructor 错误。
            Console.WriteLine("{0}'ID is {1}.", EmployeeFactory.GetNewItem().Name, EmployeeFactory.GetNewItem().ID);
        }
    }
}

new 修饰符(C# 参考)

在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。 隐藏继承的成员时,该成员的派生版本将替换基类版本。 虽然可以在不使用 new 修饰符的情况下隐藏成员,但会生成警告。 如果使用 new 显式隐藏成员,则会取消此警告,并记录要替换为派生版本这一事实。

若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并使用 new 修饰符修饰该成员。 例如:

public class BaseC
{
    public int x;
    public void Invoke() { }
}
public class DerivedC : BaseC
{
    new public void Invoke() { }
}
在此示例中,DerivedC.Invoke 隐藏了 BaseC.Invoke。 字段 x 不受影响,因为它没有被类似名称的字段隐藏。

通过继承隐藏名称采用下列形式之一:

引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成员。

引入类或结构中的方法隐藏基类中具有相同名称的属性、字段和类型。 同时也隐藏具有相同签名的所有基类方法。

引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。

对同一成员同时使用 new 和 override 是错误的做法,因为这两个修饰符的含义互斥。 new 修饰符会用同样的名称创建一个新成员并使原始成员变为隐藏的。 override 修饰符会扩展继承成员的实现。

在不隐藏继承成员的声明中使用 new 修饰符将会生成警告。

示例

 
在该例中,基类 BaseC 和派生类 DerivedC 使用相同的字段名 x,从而隐藏了继承字段的值。 该示例演示了 new 修饰符的用法。 另外还演示了如何使用完全限定名访问基类的隐藏成员。
public class BaseC
{
    public static int x = 55;
    public static int y = 22;
}

public class DerivedC : BaseC
{
    // Hide field 'x'.
    new public static int x = 100;

    static void Main()
    {
        // Display the new value of x:
        Console.WriteLine(x);

        // Display the hidden value of x:
        Console.WriteLine(BaseC.x);

        // Display the unhidden member y:
        Console.WriteLine(y);
    }
}
/*
Output:
100
55
22
*/
在此示例中,嵌套类隐藏了基类中同名的类。 此示例演示了如何使用 new 修饰符来消除警告消息,以及如何使用完全限定名来访问隐藏的类成员。
 public class BaseC 
{
    public class NestedC 
    {
        public int x = 200;
        public int y;
    }
}

public class DerivedC : BaseC { // Nested type hiding the base type members.
    new public class NestedC   
    {
        public int x = 100;
        public int y; 
        public int z;
    }

    static void Main() 
    {
        // Creating an object from the overlapping class:
        NestedC c1  = new NestedC();

        // Creating an object from the hidden class:
        BaseC.NestedC c2 = new BaseC.NestedC();

        Console.WriteLine(c1.x);
        Console.WriteLine(c2.x);   
    }
}
/*
Output:
100
200
*/
如果移除 new 修饰符,该程序仍可编译和运行,但您会收到以下警告:
The keyword new is required on 'MyDerivedC.x' because it hides inherited member 'MyBaseC.x'.

8.Extern

用于声明在外部实现的方法。 extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 特性一起使用。 在这种情况下,还必须将方法声明为 static

extern 修饰符用于声明由程序集外部实现的成员函数

经常用于系统API函数的调用(通过 DllImport )。注意,和DllImport一起使用时要加上 static 修饰符

也可以用于对于同一程序集不同版本组件的调用(用 extern 声明别名)

不能与 abstract 修饰符同时使用

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Runtime.InteropServices;
namespaceExample03
{
classProgram
{
//注意DllImport是一个Attribute Property,在System.Runtime.InteropServices命名空间中定义
//extern与DllImport一起使用时必须再加上一个static修饰符
[DllImport("User32.dll")]
publicstaticexternintMessageBox(intHandle,stringMessage,stringCaption,intType);
staticintMain()
{
stringmyString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
returnMessageBox(0, myString,"My Message Box", 0);
}
}
}

作者:viva158
链接:https://www.jianshu.com/p/bff13a1db230 

9.Readonly

修饰字段,表示该字段为只读字段。readonly是运行时只读,内容在运行时确定,所以修改了readonly类型成员后无需重新编译即可生效,Readonly不能修饰局部变量

10.Const

修饰字段,表示该字段为只读字段。const修饰的字段在编译时必须能够明确知道该字段的值,其值是硬编码到程序中去的,修改了该类型成员后需要重新编译才能使修改生效,const可以修饰局部变量

Virtual,override和new 的区别

[1] virtual和override配套使用。在基类base中声明了虚方法method()并用virtual修饰,在子类derived中重写方法method()并用override修饰。那么当将子类的实例赋予基类的对象(不需要强制转换)时即Base Bclass= new Derived();Bclass.Method()是调用了子类的method()方法,而不是基类的。

[2] new不需要和virtual配套使用。在基类base中声明了方法method(),在子类derived中声明了同名的方法method()并用new修饰。那么当将子类的实例赋予基类的对象时即Base Bclass= new Derived();Bclass.Method()是调用了基类类的method()方法,而不是子类的。

[3] 这说明,override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已。

下面,我以例子来说明他们之间的微妙区别:

基类

public class GrandClass//基类
{
        public GrandClass()
        {
                Console.WriteLine("In GrandClass.Constructor");
        }
        public virtual void Method()//用virtual才可以在子类中用override,而new不需要这样
        {
                Console.WriteLine("In GrandClass.Method()");
        }
}

继承基类,看看override状态

public class ParentClass:GrandClass//继承基类,看看override状态
{
        public ParentClass()
        {
                Console.WriteLine("In ParentClass.Constructor");
        }
        public override void Method()//使用override,是说把基类的方法重新定义
        {
                Console.WriteLine("In ParentClass.Method() use override");
        }
}

继承基类,看看new状态

public class NewParentClass:GrandClass//继承基类,看看new状态
{
        public NewParentClass()
        {
                Console.WriteLine("In NewParentClass.Constructor");
        }
        new public void Method()//使用new,不是说用到基类的方法,而是重新定义一个子类方法,只不过,方法名称与基类相同
        {
                Console.WriteLine("In NewParentClass.Method()");
        }
}

下面的调用代码:

static void Main() 
{
        GrandClass Parent=(GrandClass)new ParentClass();//用override子类加框一个基类对象句柄
        Parent.Method();
        GrandClass NewParent=(GrandClass)new NewParentClass();//用new子类加框一个基类对象句柄
        NewParent.Method();
        NewParentClass NewParent1=new NewParentClass();//一个子类句柄
        NewParent1.Method();
}

结果是这样的:

[1]In GrandClass.Constructor
[2]In ParentClass.Constructor
[3]In ParentClass.Method() use override
[4]In GrandClass.Constructor
[5]In NewParentClass.Constructor
[6]In GrandClass.Method()
[7]In GrandClass.Constructor
[8]In NewParentClass.Constructor
[9]In NewParentClass.Method()

结果前的序号是我自己加的.为了以下的分析:
  [1],[2]两句是GrandClass Parent=(GrandClass)new ParentClass();的结果.(注意一下子类构建器与基类构建器的初始化顺序)
  [3]是Parent.Method();结果.
  [4],[5]两句是GrandClass NewParent=(GrandClass)new NewParentClass();的结果.
  [6]是NewParent.Method();的结果.
  [7],[8]两句是GrandClass NewParent1=(GrandClass)new NewParentClass();的结果.
  [9]是NewParent1.Method();的结果.

  这里我们可以看到,同样是用子类的对象构造一个基类句柄.结果却很明显,可以看到[3]和[6]的区别.[3]调用了子类的Method(),而[6]调用了基类的Method().
  这说明,override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已.
     而这一例子的基础是建立在用子类对象加框成基类对象的,目的是实现用基类句柄调用子类方法,以实现重载的多态性.
  如果想调用子类的new方法,用子类的句柄(绝对不能用基类句柄)来调用.结果[9]可以看出来.
  用new是在为子类定义方法名时,实在没有办法定义方法名的情况才与基类的方法相同,但这个方法只在子类中起到作用,而不影响基类的方法.也就是说,new方法就是子类新定义的方法.用override是直正意义上的重载.  

三、base和this

C#中base关键字的几种用法:base()

https://blog.csdn.net/cplvfx/article/details/82982862

1.base关键字

/*
* base关键字
* base关键字用于从派生类中访问基类的成员;
* 指定创建派生类实例时调用基类构造函数;
* 调用基类上已被重写的方法
* 注意:不能从静态方法中使用base关键字,base关键字只能在实例构造函数、实例方法或实例访问器中使用
*/

base 关键字用于从派生类中访问基类的成员:
调用基类上已被其他方法重写的方法。
指定创建派生类实例时应调用的基类构造函数。
基类访问只能在构造函数、实例方法或实例属性访问器中进行。

base调用构造方法

public class BaseClass
        {
            public BaseClass()
            {
                Console.WriteLine("调用基类--无参数的构造函数");
            }

            public BaseClass(string name)
            {
                Console.WriteLine("调用基类--有参数的构造函数");
            }
        }

        public class DerivedClass:BaseClass
        {
            public DerivedClass()
                : base()
            {

            }
            public DerivedClass(string name)
                : base(name)
            {

            }

            static void Main()
            {
                DerivedClass a = new DerivedClass();//调用基类--无参数的构造函数
                DerivedClass b = new DerivedClass("Andy");//调用基类--有参数的构造函数
                Console.ReadLine();
            }
        }

base在派生类中调用基类的方法

 public class BaseClass
        {
           public virtual void GetInfo()
           {
                 Console.WriteLine("Andy.");
           }
        }

        public class DerivedClass :BaseClass
        {
            
            public override void GetInfo()
            {
                  base.GetInfo();//调用基类的方法,显示Andy.
                 Console.WriteLine("Chen");//显示Andy.Chen
            }

        }

关于base调用基类构造函数

public class A
{
        public A()
        {
                Console.WriteLine("Build A");
        }
}
public class B:A
{
        public B():base()
        {
                Console.WriteLine("Build B");
        }
        static void Main()
        {
                B b = new B();
                Console.ReadLine();
        }
}

创建一个B的实例对象,获得结果是同时打印Build A和Build B.

关于base在派生类中调用基类的方法。

public class A
{
        public virtual void Hello()
        {
                Console.WiriteLine("Hello");
        }
}
public class B : A
{
        public override void Hello()
        {               
                base.Hello();//调用基类的方法,显示Hello
                Console.WiriteLine("World");
        }
}

这样如果程序调用B.Hello()获得的效果将会使Hello World.

示例:1. 在派生类中调用基类方法。

using System;
public class BaseClass
{
    protected string _className = "BaseClass";
    public virtual void PrintName()
    {
        Console.WriteLine("Class Name: {0}", _className);
    }
}
class DerivedClass : BaseClass
{
    public string _className = "DerivedClass";
    public override void PrintName()
    {
        Console.Write("The BaseClass Name is {0}");
        //调用基类方法
        base.PrintName();
        Console.WriteLine("This DerivedClass is {0}", _className);
    }
}
class TestApp
{
    public static void Main()
    {
        DerivedClass dc = new DerivedClass();
        dc.PrintName();
    }
}

示例:2. 在派生类中调用基类构造函数。 

// keywords_base2.cs
using System;
public class BaseClass
{
    int num;
    public BaseClass()
    {
        Console.WriteLine("in BaseClass()");
    }
    public BaseClass(int i)
    {
        num = i;
        Console.WriteLine("in BaseClass(int {0})", num);
    }
}
public class DerivedClass : BaseClass
{
    // 该构造器调用  BaseClass.BaseClass()
    public DerivedClass()
        : base()
    {
    }
    // 该构造器调用 BaseClass.BaseClass(int i)
    public DerivedClass(int i)
        : base(i)
    {
    }
    static void Main()
    {
        DerivedClass dc = new DerivedClass();
        DerivedClass dc1 = new DerivedClass(1)();
        Console.ReadLine();
    }
}

注意:
从静态方法中使用 base 关键字是错误的。
base 主要用于面向对象开发的对态这方面,在示例2中有体现。

2. this关键字

/*
* this关键字
* this关键字引用类的当前实例
* 注意:静态成员方法中不能使用this关键字,this关键字只能在实例构造函数、实例方法或实例访问器中使用
*/

this 关键字引用类的当前实例。
以下是 this 的常用用途:
限定被相似的名称隐藏的成员
将对象作为参数传递到其他方法
声明索引器

// this 关键字
// keywords_this.cs
using System;
class Employee
{
    private string _name;
    private int _age;
    private string[] _arr = new string[5];
    public Employee(string name, int age)
    {
        // 使用this限定字段,name与age
        this._name = name;
        this._age = age;
    }
    public string Name
    {
        get { return this._name; }
    }
    public int Age
    {
        get { return this._age; }
    }
    // 打印雇员资料
    public void PrintEmployee()
    {
        // 将Employee对象作为参数传递到DoPrint方法
        Print.DoPrint(this);
    }
    // 声明索引器
    public string this[int param]
    {
        get { return _arr[param]; }
        set { _arr[param] = value; }
    }
}
class Print
{
    public static void DoPrint(Employee e)
    {
        Console.WriteLine("Name: {0}\nAge: {1}", e.Name, e.Age);
    }
}
class TestApp
{
    static void Main()
    {
        Employee E = new Employee("Hunts", 21);
        E[0] = "Scott";
        E[1] = "Leigh";
        E[4] = "Kiwis";
        E.PrintEmployee();
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("Friends Name: {0}", E[i]);
        }
        Console.ReadLine();
    }
}

base和this的综合使用

 public class MyBaseClass
    {
        public MyBaseClass()
        {
            Console.Write("调用父类无参数的构造函数");
        }

        public MyBaseClass(int i)
        {
            Console.Write("调用父类一个参数的构造函数");
        }
    }


    public class MyDerivedClass : MyBaseClass
    {
        public int age;
        public static int age2;//只要类里存在静态变量,那么静态变量总是最先初始化的。

        //静态构造函数只执行一次
        static MyDerivedClass() //既然要初始化静态变量,就要调用静态的构造函数。
        {
            age2 = 100;
            Console.Write(age2);

        }


        public MyDerivedClass()
            : this(5)//调用当前实例有参数的构造函数。如果只调用这个构造函数,那还需要调用一次基类没有参的构造函数!!!
        {
            age = 101;
            Console.WriteLine(age);
        }


        public MyDerivedClass(int i) : base(i)//调用基类有参数的构造函数
        {
            age = 102;
            Console.WriteLine(age);
        }

        public MyDerivedClass(int i, int j)
        {
            Console.WriteLine("两个变量的参数");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyDerivedClass myder = new MyDerivedClass(); //输出100 ,"调用父类无参数的构造函数",101
            //执行顺序:<1>: static MyDerivedClass() <2>: public MyBaseClass() <3>:public MyDerivedClass()

            //---------------------------------------------------------------------------------------------

            MyDerivedClass myder2 = new MyDerivedClass(5); //输出"调用父类无参数的构造函数",102。

            //在初始化myder对象的时候已经初始化过静态变量age2了。因为静态构造函数最多执行一次,所以初始化myder2对象的时候就不会在继续初始化静态变量age2了
            //执行顺序:<1>: public MyBaseClass() <2>: public MyDerivedClass(int i)


            //假如我想在初始化myder2对象的时候调用父类带有一个参数的构造函数怎么办呢?很好办只要在派生类的构造函数后面加一个:base(i)
            /*     base 关键字用于从派生类中访问基类的成员;指定创建派生类实例时应调用的基类构造函数。
              
                     public MyDerivedClass(int i):base(i)
                     {
                        age = 102;
                        Console.WriteLine(age);
                     }
                     
                    执行顺序:<1>: public MyBaseClass(int i) <2>: public MyDerivedClass(int i)
                    顾这里输出的是 "调用父类一个参数的构造函数",102
             */
            //---------------------------------------------------------------------------------------------

            MyDerivedClass myder3 = new MyDerivedClass(5, 6); //输出"调用父类无参数的构造函数","两个变量的参数"
            //执行顺序:<1>: public MyBaseClass() <2>: public MyDerivedClass(int i, int j)
 
            Console.ReadKey();
        }
    }

更多请看

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/modifiers 

参考:

C# 之 4个访问修饰符和8个声明修饰符详解

https://www.cnblogs.com/xinaixia/p/5775471.html

C#的修饰符

https://www.cnblogs.com/luna-hehe/p/9174439.html

C#关键字之重载overload、重写override、覆写overwrite(new)详解

https://blog.csdn.net/cplvfx/article/details/83309883

C#中base关键字的几种用法:base()

https://blog.csdn.net/cplvfx/article/details/82982862 

C# base和this的用法

https://www.cnblogs.com/AndyChen2015/p/7927575.html?tdsourcetag=s_pctim_aiomsg

猜你喜欢

转载自blog.csdn.net/cplvfx/article/details/85677995