C#基础知识(base、this、new、override、abstract、virtual、static)
前言
本文主要来讲解一下C#中,自己觉得掌握的不怎么样或者用的不多,不太熟悉的关键字,主要包括base、this、new、override、abstract、virtual以及针对static字段和static构造函数之间的执行问题。
base关键字
base 关键字用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数、实例方法和实例属性访问器中:
调用基类上已被其他方法重写的方法。

public class Father
{
public virtual void Say()
{
Console.WriteLine("Father Say");
}
} public class Son : Father
{
public override void Say()
{
base.Say();
Console.WriteLine("Son Say");
}
}

指定创建派生类实例时应调用的基类构造函数。

public class Father
{
public string Name { get; set; } public Father()
{
Name = "Father";
}
} public class Son : Father
{
public Son()
: base()
{ }
}

从静态方法中使用 base 关键字是错误的。
this关键字
其用于引用类的当前实例,也包括继承而来的方法,通常可以隐藏this:
- 限定被相似的名称隐藏的成员

public class Person
{
public string Name { get; set; } public int Age { get; set; } public Person(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
}
}

- 将对象作为参数传递到其他方法

public class Person
{
public string Name { get; set; } public int Age { get; set; } public Person(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
}
public void CallTest(Person person)
{
Console.WriteLine(person.Name+person.Age);
} public void Call()
{
CallTest(this);
}
}

- 声明索引器

public class Person
{
string[] PersonList = new string[10];
public string this[int param]
{
get { return PersonList[param]; }
set { PersonList[param] = value; }
}

new关键字
一、new运算符
1、new一个class时,new完成了以下两个方面的内容:一是调用new class命令来为实例在托管堆中分配内存;二是调用构造函数来实现对象初始化。
2、new一个struct时,new运算符用于调用其带构造函数,完成实例的初始化。
3、new一个int时,new运算符用于初始化其值为0。
4、 new运算符不可重载。
5、new分配内存失败,将引发OutOfMemoryException异常。
二、new修饰符
new 关键字可以显式隐藏从基类继承的成员。 隐藏继承的成员时,该成员的派生版本将替换基类版本。 虽然可以在不使用 new 修饰符的情况下隐藏成员,但会生成警告。 如果使
用 new 显式隐藏成员,则会取消此警告,并记录要替换为派生版本这一事实。
在子类中用 new 关键字修饰 定义的与父类中同名的方法,叫覆盖。 覆盖不会改变父类方法的功能。

public class A
{
public virtual void Test()
{
Console.WriteLine("A.Test()");
}
} public class B : A
{
public new void Test()
{
Console.WriteLine("B.Test()");
}
} class Program
{
static void Main(string[] args)
{
A a = new A();
a.Test();
B b = new B();
b.Test();
A c = new B();
c.Test();
Console.ReadLine();
}
}
}

当用子类创建父类的时候,如 A c = new B(),覆盖不会改变父类的功能,仍然调用父类功能。(和override有区别,下面进行讲解)
三、new 约束
new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。 如果要使用 new 约束,则该类型不能为抽象类型。
当与其他约束一起使用时,new() 约束必须最后指定:
public class ClassA<T>where T : IComparable, new()
{
////
}
override关键字
要扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符。
由 override 声明重写的方法称为重写基方法。 重写的基方法必须与 override 方法具有相同的签名。
不能重写非虚方法或静态方法。 重写的基方法必须是 virtual、abstract 或 override 的。
用关键字 virtual 修饰的方法,叫虚方法。可以在子类中用override 声明同名的方法,这叫“重写”。相应的没有用virtual修饰的方法,我们叫它实方法。 重写会改变父类方法的功能。

public class A
{
public virtual void Test()
{
Console.WriteLine("A.Test()");
}
} public class B : A
{
public override void Test()
{
Console.WriteLine("B.Test()");
}
} class Program
{
static void Main(string[] args)
{
A a = new A();
a.Test();
B b = new B();
b.Test();
A c = new B();
c.Test();
Console.ReadLine();
}
}

new 和override
1、 不管是重写还是覆盖都不会影响父类自身的功能。
2、当用子类创建父类的时候,如 A c = new B(),重写会改变父类的功能,即调用子类的功能;而覆盖不会,仍然调用父类功能。
3、虚方法、实方法都可以被覆盖(new),抽象方法,接口 不可以。
4、抽象方法,接口,标记为virtual的方法可以被重写(override),实方法不可以。
5、重写使用的频率比较高,实现多态;覆盖用的频率比较低,用于对以前无法修改的类进行继承的时候。
abstract关键字
针对abstract关键字暂时总结了以下五点:
1.用关键字abstract定义的类即为抽象类,且只能作为基类,也不能被实例化。
2.用abstract定义的类不一定包含抽象方法,也可以包含非抽象方法。
3.abstract定义的方法一定包含在抽象类中。
4.抽象类不能定义为密封类(sealed),抽象方法不能使用virtual、static、private修饰符
5.如果派生类没有实现所有的抽象方法,则该派生类也必须声明为抽象类。
virtual关键字
Virtual方法(虚方法)
virtual 关键字用于在基类中修饰方法。virtual的使用会有两种情况:
情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
static字段和static构造函数
主要来说明执行的顺序:
1、编译器在编译的时候,先分析所需要的静态字段,如果这些静态字段所在的类有静态的构造函数,那么就会忽略字段的初始化;如果没有静态的构造函数,那么就会对静态字段进行初始化。
2、如果存在多个静态类,那么初始化的静态成员的顺序会根据引用的顺序,先引用到的先进行初始化,但如果类的静态成员的初始化依赖于其他类的静态成员,则会先初始化被依赖的静态成员。
3、而带有静态构造函数的类的静态字段,只有在引用到的时候才进行初始化。
下面我们来看两个简单的小例子:

public class A
{
public static int X = B.Y+1;
static A() { }
} public class B
{
public static int Y=A.X+1;
} class Program
{
static void Main(string[] args)
{
Console.WriteLine("A.X={0},B.Y={1}",A.X,B.Y);
Console.ReadLine();
}
}

结果如何呢?再来看第二个小例子:

public class A
{
public static int X = B.Y+1;
} public class B
{
public static int Y=A.X+1;
static B() { }
} class Program
{
static void Main(string[] args)
{
Console.WriteLine("A.X={0},B.Y={1}",A.X,B.Y);
Console.ReadLine();
}
}

对比一下,这两个例子,如果你想的和你执行后的结果一致,那说明你应该已经明白它们的执行顺序了。
abstract、virtual、override 和 new 是在类的继承关系中常用的四个修饰方法的关键字,在此略作总结。
1. 常用的中文名:abstract 抽象方法,virtual 虚方法,override 覆盖基类方法,new 隐藏基类方法,override 和 new 有时都叫重写基类方法。
2. 适用场合:abstract 和 virtual 用在基类(父类)中;override 和 new 用在派生类(子类)中。
3. 具体概念:
abstract 抽象方法,是空方法,没有方法体,派生类必须以 override 实现此方法。
virtual 虚方法,若希望或预料到基类的这个方法在将来的派生类中会被重写(override 或 new),则此方法必须被声明为 virtual。
override 重写继承自基类的 virtural 方法,可以理解为拆掉老房子,在原址上建新房子,老房子再也找不到了(除非显式地用 base. 调用基类方法)。
new 隐藏继承自基类的 virtual 方法,老房子还留着,在旁边盖个新房,想住新房住新房(作为派生类对象调用),想住老房住老房(作为基类对象调用)。
当派生类中出现与基类同名的方法,而此方法前面未加 override 或 new 修饰符时,编译器会报警告,但不报错,真正执行时等同于加了 new。
4. abstract 和 virtual 的区别:abstract 方法还没实现,连累着基类也不能被实例化,除了作为一种规则或符号外没啥用;virtual 则比较好,派生类想重写就重写,不想重写就吃老子的。而且继承再好也是少用为妙,继承层次越少越好,派生类新扩展的功能越少越好,virtual 深合此意。
5. override 和 new 的区别:当派生类对象作为基类类型使用时,override 的执行派生类方法,new 的执行基类方法。如果作为派生类类型调用,则都是执行 override 或 new 之后的。
演示 override 和 new 区别的例子:

// Define the base class
class Car
{
public virtual void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
}
}
// Define the derived classes
class ConvertibleCar : Car
{
public new virtual void DescribeCar()
{
base.DescribeCar();
System.Console.WriteLine("A roof that opens up.");
}
}
class Minivan : Car
{
public override void DescribeCar()
{
base.DescribeCar();
System.Console.WriteLine("Carries seven people.");
}
}
public static void TestCars1()
{
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}

输出类似如下所示:
Four wheels and an engine.
----------
Four wheels and an engine.
A roof that opens up.
----------
Four wheels and an engine.
Carries seven people.
----------
但是,如果我们声明一个从 Car 基类派生的对象的数组。此数组能够存储 Car、ConvertibleCar 和 Minivan 对象,如下所示:

public static void TestCars2()
{
Car[] cars = new Car[3];
cars[0] = new Car();
cars[1] = new ConvertibleCar();
cars[2] = new Minivan();
}

然后用一个 foreach 循环来访问该数组中包含的每个 Car 对象,并调用 DescribeCar 方法,如下所示:

foreach (Car vehicle in cars)
{
System.Console.WriteLine("Car object: " + vehicle.GetType());
vehicle.DescribeCar();
System.Console.WriteLine("----------");
}

此循环的输出如下所示:
Car object: YourApplication.Car
Four wheels and an engine.
----------
Car object: YourApplication.ConvertibleCar
Four wheels and an engine.
----------
Car object: YourApplication.Minivan
Four wheels and an engine.
Carries seven people.
----------
注意,ConvertibleCar 的说明可能与您的预期不同。由于使用了 new 关键字来定义此方法,所调用的不是派生类方法,而是基类方法。Minivan 对象正确地调用重写方法,并产生预期的结果。
C#基础知识(base、this、new、override、abstract、virtual、static)的更多相关文章
- 【C#】override,Abstract,Virtual 介绍及区别--转载
要扩展或修改继承的方法.属性.索引器或事件的抽象实现或虚实现,必须使用 override 修饰符. 1. override 方法提供从基类继承的成员的新实现.通过 override 声明重写的方法称为 ...
- JAVA核心技术I---JAVA基础知识(查漏补缺private,static)
一:private对于类和对象(同C++) private是只有这个类内部可以访问(类的成员函数和定义初始化) private是类之间的限制,而不是对对象的限制<重点> 同类对象是可以直接 ...
- vue项目构建实战基础知识:SPA理解/RESTful接口介绍/static目录配置/axios封装/打包时map文件去除
一.SPA 不是指水疗.是 single page web application 的缩写.中文翻译为 单页应用程序 或 单页Web应用,更多解释请自行搜索. 所有的前端人员都应该明白我们的页面的 u ...
- 基础知识系列☞Abstract和Virtual→及相关知识
转载地址→http://www.cnblogs.com/blsong/archive/2010/08/12/1798064.html 在C#的学习中,容易混淆virtual方法和abstract方法的 ...
- C#基础知识一之base关键字
前言 其实很早就想写关于C#基础,总是自己给自己找借口,或者去网上搜搜看看,现在想想觉得自己有点懒惰... 作为开发人员,基础知识是重中之重的,只有巩固.理解.实践才能提高自身的技能.同时也希望通过 ...
- Data Base sqlServer基础知识
sqlServer 基础知识 大纲 创建数据库 1 创建表 2 备份表 3 删除表 4 修改表 5 查询出重复的数据 6 增删改查 7 添加约束 8 分页存储过程 9 排序 10 类型转换 11 ...
- 基础才是重中之重~方法override详解
回到 目录 之所以写这篇文章,完全是因为这次代码审核,这次代码审核过程当中,出现了很多我认为基础知识不够扎实的问题,所以,打算把它们记录下来,共大家分享. 方法的override,即方法的覆写或者重写 ...
- 【RAC】RAC相关基础知识
[RAC]RAC相关基础知识 1.CRS简介 从Oracle 10G开始,oracle引进一套完整的集群管理解决方案—-Cluster-Ready Services,它包括集群连通性.消息和锁. ...
- ASP.NET基础知识汇总之WebConfig自定义节点详细介绍
之前介绍过Webconfig的具体知识ASP.NET基础知识汇总之WebConfig各节点介绍.今天准备封装一个ConfigHelper类,涉及到了自定义节点的东东,平时虽然一直用,但也没有系统的总结 ...
随机推荐
- [COCI2009]Dvapravca 计算几何
[COCI2009]Dvapravca LG传送门 先给出考场上的\(O(n^3)\)乱搞方法:枚举一个蓝点和一个红点,找出过着两个点的直线,再枚举蓝点找出这条直线最多能往两边扩展多宽,最后枚举红点计 ...
- LUOGU3278 [SCOI2013]多项式的运算
一次AC.吼啊. BZOJ权限QAQ 区间加和乘打标记,区间乘x就是区间移动,平衡树解决即可. 查询直接遍历一遍然后算出来 // It is made by XZZ #include<cstdi ...
- 用C链表实现约瑟夫环问题
问题:设有n个人围成一个圆圈,现从第s个人开始报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到第m的人再次出列,如此反复,直到所有的人全部出列为止.对于任意给定的n.s.m,求按出列次序 ...
- AutomaticInteger中CAS运用分析
摘要 在接触CAS的时候虽然对它流程了解了但是对其如何解决并发问题还是一直有疑问的,所以在就选择了java中典型线程安全的AtomicInteger类进行了源码的分析. CAS简介 CAS的全称为co ...
- cpp-variable-lifetime
#include <cstdio> #include <iostream> using namespace std; class TmpClass; void FuncScop ...
- kubenetes无法创建pod/创建RC时无法自动创建pod的问题
一.问题概述 问题1: 虽然每次通过yaml创建rc都显示成功了,但是 kubectl get pod却没显示任何的pod. 问题2: 直接通过yaml创建pod提示apixxx 问题3: 通过.js ...
- UNITY_委托和事件
UNITY_委托和事件 参考资料: Unity3D脚本编程-使用C#语言开发跨平台游戏-陈嘉栋 观察者模式 主题(Subject)管理某些数据,当主题的数据发生改变时,会通知已经注册(Register ...
- kali虚拟机安装后操作[配置ssh,安装vmtools,更新源]
更新源 # 打开控制台, 输入以下命令打开编辑器修改配置文件 $ leafpad /etc/apt/sources.list #kali官方源 deb http://http.kali.org/kal ...
- oracle 数据库的详细安装教程
由于oracle数据库比较大 所以安装的时候比较慢是目前装的最大的软件了吧 而且如果装崩了 可能还会重装系统 不过比较幸运 一次就装好 1.需要去官网下载 https://www.oracle.co ...
- git解决代码提交冲突
树冲突文件名修改造成的冲突,称为树冲突.比如,A同事把文件改名为A.C,B同事把同一个文件改名为B.C,那么B同事将这两个commit合并时,会产生冲突.如果最终确定用B同事的文件名,那么解决办法如下 ...