最近感觉自己C#基础不够扎实,所以又回去看了一些C#的基础知识,这里主要讲解一下比较用的到的this和base的用法。
this是对象级别的使用,指向的是当前实例化的对象,主要有三种用法:
第一种,在实例化构造函数的时候,为了避免传入的参数跟类的字段同名,使用this来区分开,避免混乱。
class MyClass { private int age; private string name; public MyClass(int age, string name) { this.age = age; this.name = name; } }
这里this.age的age是MyClass的字段age。
第二种,在构造函数链里面使用,在类的一个构造函数中,通过this指向一个主构造函数。
这种用法主要是为了避免实例化构造函数需要传入太多参数值。在调用的过程中,先去调用主构造函数,完了以后再调用自己的构造函数。
class MyClass { private int age; private string name; private bool sex; private string address; public MyClass(int age, string name) { this.age = age; this.name = name; } public MyClass(int age, bool sex)
: this("", sex, "") { this.age = age; } //这里写一个主构造函数 public MyClass(string name, bool sex, string address) { this.name = name; this.sex = sex; this.address = address; } }
第二个构造函数,传入了age和sex两个参数,在执行的时候会先调用下面的主构造函数,给name,sex和address赋值,完了再回来执行当前的构造函数,给age赋值
第三种是用在扩展方法中,在第一个参数前面加上this,表示对改类型的一个扩展
public static List<ShipMethod> GetSupportedShipMethods(this PlatformType platformType) { List<ShipMethod> methods = null; var log = new LogisticsServiceNameAttribute(); switch (platformType) { case PlatformType.速卖通: methods = Enum.GetValues(typeof(Somitech.Entity.ShipMethod)).Cast<ShipMethod>() .Where(s => s.HasAttribute(typeof(LogisticsServiceNameAttribute)) && !s.HasAttribute(typeof(ObsoleteAttribute)) && s.GetLogisticsServiceName().AliExpress != null).ToList(); break; case PlatformType.敦煌: methods = Enum.GetValues(typeof(Somitech.Entity.ShipMethod)).Cast<ShipMethod>() .Where(s => s.HasAttribute(typeof(LogisticsServiceNameAttribute)) && !s.HasAttribute(typeof(ObsoleteAttribute)) && s.GetLogisticsServiceName().DhGate != null).ToList(); break; default: throw new NotImplementedException(platformType.ToString()); } methods = methods.ToList(); return methods; }
base是类级别的,指向基类,比较常用的用法也有两种:
第一种,在派生类的构造函数中调用基类的构造函数。
我们知道在派生类的实例化过程中,会先去调用基类的构造函数,正常是调用默认构造函数,这里我们可以指定调用哪个构造函数。
执行顺序是,先执行基类的带参数的构造函数,然后再执行派生类的构造函数。
public class MyBaseClass { public MyBaseClass() { Console.WriteLine("基类无参构造函数!"); } public MyBaseClass(int num) { Console.WriteLine("基类带有整型参数的构造函数!"); } } public class MyClass : MyBaseClass { public int age; public MyClass() { } //派生类调用基类带参数的构造函数,这里会调用MyBaseClass(int num)这个方法 public MyClass(int num) : base(num) { age = 102; Console.WriteLine("派生类带有整型参数的构造函数!age=" + age); } }
在MyClass类的构造函数MyClass(int num)被调用的时候,会先去调用基类中的构造函数MyBaseClass(int num)
第二种,在派生类的方法中调用已经被重写的基类的方法。
public class MyBaseClass { public MyBaseClass() { Console.WriteLine("基类无参构造函数!"); } public MyBaseClass(int num) { Console.WriteLine("基类带有整型参数的构造函数!"); } public virtual void GetMyAge() { Console.WriteLine("我是基类,我的年龄最大!"); } } public class MyClass : MyBaseClass { public int age; //派生类调用基类带参数的构造函数,这里会调用MyBaseClass(int num)这个方法 public MyClass(int num) : base(num) { age = 102; Console.WriteLine("派生类带有整型参数的构造函数!age=" + age); } public override void GetMyAge() {
base.GetMyAge(); Console.WriteLine("我是派生类,我的年龄比较小!"); } }
这里,我们再子类的GetMyAge方法中通过base.GetMyAge()来调用基类的被重写的方法,执行完基类方法以后,再执行方法剩下的部分。
会输出:
我是基类,我的年龄最大!
我是派生类,我的年龄比较小!
最后,我们再通过一个控制台项目来结合this和base的用法使用一下,在控制台输入以下代码:
新建一个MyBaseClass的基类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DesignPatterns.Basic { public class MyBaseClass { public MyBaseClass() { Console.WriteLine("基类无参构造函数!"); } public MyBaseClass(int num) { Console.WriteLine("基类带有整型参数的构造函数!"); } public virtual void GetMyAge() { Console.WriteLine("我是基类,我的年龄最大!"); } } }
再新建一个子类MyClass:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DesignPatterns.Basic { public class MyClass : MyBaseClass { public int age; public static int age2; public static readonly object obj = new object(); static MyClass() { age2 = 100; Console.WriteLine("执行静态构造函数!age2=" + age2); } public MyClass() : this(5) { age = 101; Console.WriteLine("派生类无参构造函数!age=" + age); } public MyClass(int num) : base(num) { age = 102; Console.WriteLine("派生类带有整型参数的构造函数!age=" + age); } public MyClass(int num, int kit) { Console.WriteLine("派生类带有两个参数的构造函数"); } public override void GetMyAge() { base.GetMyAge(); Console.WriteLine("我是派生类,我的年龄比较小!"); } } }
最后在Program文件的Main函数中输入以下代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DesignPatterns.Basic; namespace DesignPatterns { class Program { static void Main(string[] args) { //执行顺序是:静态构造函数 =》 基类带有参数的构造函数 =》派生类带有参数的构造函数 =》派生类无参构造函数 MyClass myClass = new MyClass(); //执行顺序是:基类带有参数的构造函数 =》 派生类带有参数的构造函数 MyClass myClass1 = new MyClass(10); Console.ReadKey(); } } }
在这里,我们在子类中添加了三个字段,一个普通字段age,两个静态字段age2和obj,这里先讲讲静态字段的用法。
静态字段跟静态方法一样是通过类来调用的,所有的对象共享这个静态字段,这个字段一旦被初始化以后就不能再次赋值了,我们可以在申明的时候就去初始化,比如obj。如果在申明的时候没有初始化,那只能通过静态构造函数去初始化,比如age2。
一个类中如果存在静态构造函数,那么静态构造函数会被优先调用,而且只会被执行一次,真实的执行过程是:每次执行实例化构造函数的时候,都会去判断静态构造函数是否有被执行,如果没有就执行优先执行静态构造函数,如果执行了,就不再去执行。
所以在执行下面这个代码的时候,其实走了4步:MyClass myClass = new MyClass();
首先调用静态构造函数,给静态变量age2赋值,然后调用派生类的构造函数public MyClass() : this(5),但是因为这个构造函数通过this指向了主构造函数,所以需要先去调用主构造函数public MyClass(int num) : base(num),而主构造函数又通过base去调用了基类的带参数的构造函数public MyBaseClass(int num),执行顺序是:静态构造函数 =》 基类带有参数的构造函数 =》派生类带有参数的构造函数 =》派生类无参构造函数
正确的输出:
在执行MyClass myClass1 = new MyClass(10);这个方法的时候就简单多了,因为静态构造函数上面已经执行了,所以这里就不再执行。
顺序:基类带有参数的构造函数 =》 派生类带有参数的构造函数
以上就是大概base和this的用法了,这两个的用法主要都是为了方便我们少写一些代码。