int? , 表示可空类型,即是值可以为null
int i = default(int);//默认值为0 int? j = default(int?);//默认值为nullNull 与任何运算符运算都是null
j = null; int? k = j + 5;//k值为null数据样式:
c:货币d:十进制f:浮点P: 百分比e:科学记数法类包括数据成员和函数成员
与类平级的预定义类型
类结构枚举数组委托接口C # 与C++ 等有所不同,C# 没有全局变量的概念,即函数不能再类外声明,同样的,C#中也没有默认的返回类型,必须是指定的返回类型或者 void。
类的声明,是用来构建类的蓝图,一旦被声明,即可构建类的实例。既然要实例化一个类,就要用类的引用和实际数据都申请内存。
NewClass A = new NewClass();实例化一个类,就要分配一个空间,分配空间,就要用new关键字,而且后边要跟()
在类的内部,任何成员之间都可以相互访问。
private:(不带访问符号,默认就是私有成员) 只能他自己的类访问public:protected:允许自己和派生类可以访问internal:程序集内部可见protected internal:派生类 或 程序集内部可见引用参数
public int Add(ref int a, ref int b)输出参数
void Method (out int a) static void Main(string[] args) { int sum; Add(out sum, 5, 8); Console.WriteLine(sum); } public static void Add(out int c, int a, int b) { c = a + b; }与引用参数不同,输出参数有以下要求:
输出参数在被读取之前,必须先被赋值。在方法返回之前,方法内部任何可能路径,都必须为所有输出参数赋值一次。数组参数
“数组参数”和数组是两码事,注意区分
一个参数列表里,只能有一个数组参数,而且必须放在最后数组参数的所有参数都必须有相同的类型声明方法如下:
void Method(int a,params int[] mm)上边看到的都是位置参数,也就是说每个形参的位置都应该和实参的位置一一对应,除此之外,还可以使用命名参数,这样就可以任意顺序调用参数了。
Method(a: 3, b: 6, c: 3);即给参数提供默认值
void Method(int a,int b=3) { }如果这几种参数都存在的话,他们的声明的顺序之间的关系,如下图:
即在 new 对象的时候,就对里面的一些属性和字段赋值
注意写法
class ClassA { public int A { get; set; } public int B { get; set; } } // 对象初始化语句 ClassA classA = new ClassA () { A = 9, B = 3; } // 如果选择使用没有参数的构造函数,后面的()可以直接不写。 ClassA classA = new ClassA { A = 9, B = 3; }对比实例构造函数的方法的声明方式,注意区分
class ClassA { public int Id { get; set; } public string Name { get; set; } public ClassA(int id) { Id = id; } } ClassA classA = new ClassA(3);派生类不能删除他继承的任何成员,但是可以用与其基类名称相同的成员来屏蔽基类成员。(此时,要让编译器知道你在故意屏蔽继承的成员,所以要用 new 修饰符,否则编译器会弹出警告。)
class SomeClass { public string str { get; set; } } class OtherClass : SomeClass { new public string str { get; set; } }如果基类必须要完整的访问被隐藏的基类,可以可以使用 基类访问表达式 访问隐藏的基类
基类的表达式是由关键字 base 后边跟一个点和成员的名字组成。
class SomeClass { public string str = "SomeClass 类"; public void Method1(string value) { Console.WriteLine($"SomeClass 中的 {value}"); } } class OtherClass : SomeClass { new public string str = "OtherClass"; public void Method2(string value) { Console.WriteLine($"OtherClass中的 {base.str}"); } }如果你代码中,经常使用这个特性(即访问隐藏的继承类),那么你可能要重新评估类的设计了,一般来说,都是在没有其他办法的时候,使用这个特征。
上边无论是 base 还是 强制类型转换 ,都是使用子类调用父类的方法,如果想用父类调用子类的方法,就要用到 虚方法
class Program { static void Main(string[] args) { OtherClass otherClass = new OtherClass(); SomeClass someClass = (OtherClass)otherClass; someClass.Print(); otherClass.Print(); } } class SomeClass { virtual public void Print() { Console.WriteLine("这是基类"); } } class OtherClass : SomeClass { override public void Print() { Console.WriteLine("这是派生类"); } } 输出: 这是派生类 这是派生类注意:
覆写和被覆写的方法,都必须有相同的可访问性,不能被覆写的是 private ,而覆写的是 public不能覆写 static 和非虚方法。这种方法,只能在类型转换过程中,才能使用,直接引用无效。创建一个实例的过程如下:
class SomeClass { virtual public void Print() { Console.WriteLine("这是基类"); } } class OtherClass : SomeClass { int MyFiled1 = 5; // 成员初始化 int MyFiled2; public OtherClass() // 构造函数执行,调用基类的无参构造函数 SomeClass() { } override public void Print() { Console.WriteLine("这是派生类"); } }默认情况下,在构造对象的时候,会调用基类无参数的构造函数,但是构造函数可以重载,有可能有多个构造参数,所以如果派生类使用一个指定的基类构造函数,就要在构造函数初始化语句 中使用他。
有两种形式:
使用关键字 base 并指明使用哪一个基类构造函数。使用关键字 this 指明应该使用当前类的哪一个构造函数。base的用法:
class SomeClass { public string someClassString; public SomeClass() // 这个无参的构造函数不能省 { } public SomeClass(string a) { someClassString = a; } } class OtherClass : SomeClass { int MyFiled1 = 5; // 成员初始化 int MyFiled2; public OtherClass(string a ):base(a) // 把构造函数,从子类传到父类。 { } }抽象成员是指被设计为要被覆写的函数成员。他具有以下特征
必须是一个函数成员。字段和常量不行。必须要用 abstract 修饰符。不能有实现的代码块。抽象成员只能在抽下类中声明。 abstract public void PrintStuff(string s);虚成员和抽象成员的比较
虚成员抽象成员关键字virtualabstract实现体实现体没有实现体在派生类中覆写能被覆写,使用 override必须被覆写,使用 override成员的类型属性,事件,方法 ,索引器属性,事件,方法 ,索引器抽象类是指定被继承的类。抽象类只能做其他类的基类
就是用来被继承的(只能用作其他类的基类)不能被实例化上边讲,抽象类必须用作基类,不能被实例化,而密封类恰恰与他相反。
密封类只能用作独立的类,不能用作基类密封类使用 sealed 修饰符[1]https://blog.csdn.net/weixin_38211198/article/details/96841992
