第七章 类与继承
1、虽然派生类不能删除基类的的任何成员,但我们可以利用在派生类当中声明与基类成员名称相同的成员来屏蔽基类成员。这叫 覆盖。
一种是隐式屏蔽。一种是显式屏蔽。所谓 显式就是 加上一个new 关键字即可。此new 可以放在字段前面,也可以放在方法前面。
此时,如果我们还是想访问基类成员,可以使用基类访问方式实现。base. Xxxx 来实现 访问隐藏的继承成员。
2、虚方法与覆写方法
这部分内容和C++里面的 虚函数与抽象类类似,而含有纯虚函数的类属于抽象类。
这里面有个神奇的地方是,使用基类的引用竟然可以访问派生类的方法。
3、构造函数的执行
初始化实例成员----- 调用基类的构造函数 ------ 执行实例构造函数的方法体。
4、类访问修饰符
Public internal
成员访问修饰符
Public private protected internal protected internal.
Public: 共有类的公有成员对同一程序集和不同程序集的所有类都是可见的。
Private:任何类的私有成员只对它自己的类或者嵌套类的成员可见。
Protected :
Internal:
Protected internal:
5、抽象类
与抽象类相同,还有抽象方法,抽象属性,相当于纯虚函数一样。
-
class SomeClass
-
{
-
public string field1 = "some class field";
-
int myint = 5;
-
virtual public int MyProperty
-
{
-
get { return myint; }
-
}
-
virtual public void Method1(string value)
-
{
-
Console.WriteLine("{0}", value);
-
}
-
}
-
class OtherClass : SomeClass //继承
-
{
-
new public string field1 = "Other class field"; //成员的覆盖
-
int myint = 10;
-
//new public void Method1(string value) //方法的屏蔽
-
//{
-
// Console.WriteLine("{0}", value);
-
//}
-
override public void Method1(string value) //方法的覆盖
-
{
-
Console.WriteLine("{0}", value);
-
}
-
override public int MyProperty
-
{
-
get { return myint; }
-
}
-
public void Print()
-
{
-
Console.WriteLine("{0}", base.field1);//即使基类成员和方法被派生类覆盖,我们也可以
-
//使用基类访问来调用基类的成员和方法。
-
}
-
}
-
-
-
//调用
-
//1、派生类是相对的,所有的类都派生于object基类,只是隐藏了 : object
-
//2、实例变量与方法的覆盖,用关键字new实现
-
OtherClass other = new OtherClass();
-
other.Method1(other.field1);
-
other.Print();//使用基类访问来调用基类的成员或方法
-
//3、使用基类的引用,通过转换引用实现
-
SomeClass some = (SomeClass)other;//转换引用
-
some.Method1(some.field1);
-
//问题:派生类可以调用基类的方法,那么基类能否调用派生类的方法
-
//可以,使用virtual和override关键字
-
//适用与其他成员类型
-
Console.WriteLine(other.MyProperty);
-
Console.WriteLine(some.MyProperty);
-
//4、构造函数初始化语句 :this() 加在基类构造函数后面。派生类中,指明即可。or :base(s,x) 指在派生类中调用指定的基类的构造函数。
-
//5、类访问修饰符
-
//public (可以被系统内任何程序集中的代码访问)与 internal(这个不允许其他程序集中的类访问内部类)
-
//6、支持程序集间的继承,利用using添加对该基类程序集的引用
-
abstract class Mybase
-
{
-
public int SideLength = 10; //数据成员
-
const int TriangleSideCount = 3;
-
abstract public void PrintStuff(string s);//抽象方法
-
abstract public int MyInt { get; set; }//抽象属性
-
public int PerimeterLength()//普通的非抽象方法
-
{
-
return TriangleSideCount * SideLength;
-
}
-
}
-
class MyClass1 : Mybase
-
{
-
public override void PrintStuff(string s)
-
{
-
Console.WriteLine(s);
-
}
-
private int myint;
-
public override int MyInt
-
{
-
get
-
{
-
return myint;
-
}
-
set
-
{
-
myint = value;
-
}
-
}
-
}
-
-
//调用
-
//7、抽象成员
-
//必须加abstract 可以在方法 属性 事件 索引共4个类型的成员前面加
-
//其只可以在抽象类中声明,不能加virtual,实现必须加override。
-
//抽象类,只能被继承。
-
-
MyClass1 mc1 = new MyClass1();
-
mc1.PrintStuff("hello world!");
-
mc1.MyInt = 100;
-
Console.WriteLine(mc1.MyInt);
-
-
//8、密封类,与抽象类相反,无法用作基类 关键字sealed。无法被继承。跟final 有点像。
-
//9、静态类
-
//static 类,其成员必须是静态的。一般为了建立一组不变的数学库或数学方法
-
sealed class MyData //sealed 修饰符说明此类不能被继承
-
{
-
private double d1, d2, d3;
-
public MyData(double m1, double m2, double m3)
-
{
-
d1 = m1;
-
d2 = m2;
-
d3 = m3;
-
}
-
public double Sum()
-
{
-
return d1 + d2 + d3;
-
}
-
}
-
static class ExtendMyData //扩展方法,创建另一个作用于MyData类的实例
-
{
-
public static double Average(this MyData md)//关键字和类型。加上this 就可以利用实例调用形式调用方法了
-
{ //而不是用静态调用形式:ExtendMyData.Average(md);
-
return md.Sum() / 3;
-
}
-
}
-
-
//调用
-
//10、扩展方法
-
MyData md = new MyData(1, 2, 3);
-
Console.WriteLine(md.Sum());
-
Console.WriteLine(md.Average());
-
//11.命名约定
-
//CardDeck 这种一般用于类,方法,命名空间,属性和公共字段
-
//totalCycle 这种一般用于局部变量或者形参
-
//_cycleCount 一般用于事件,私有和受保护的字段
第八章 表达式与运算符
1、比较
浅比较:比较引用 深比较:比较内容。
2、用户定义的类型转换
隐式转换如下:
Public static implicit operator TargetType (SourceType Identifier)
{
Xxxxxx
Return ObjectOftargetType;
}
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Text;
-
-
namespace CsharpStart //运算符重载
-
{
-
class LimitenInt
-
{
-
const int MaxValue = 100;
-
const int MinValue = 10;
-
-
private int _theValue = 0;
-
public int TheValue //属性值
-
{
-
get
-
{
-
return _theValue;
-
}
-
set
-
{
-
if (value < MinValue)
-
{
-
_theValue = 0;
-
}
-
else
-
{
-
_theValue = value > MaxValue ? MaxValue : value;
-
}
-
}
-
}
-
// 必需的,public static + 类型 + 关键字 + 运算符 + (操作数)
-
public static LimitenInt operator -(LimitenInt x)
-
{
-
//去一个值的负数为0
-
LimitenInt li = new LimitenInt();
-
li.TheValue = 0;
-
return li;
-
}
-
-
public static LimitenInt operator -(LimitenInt x, LimitenInt y)
-
{
-
LimitenInt li = new LimitenInt();
-
li.TheValue = x.TheValue - y.TheValue;
-
return li;
-
}
-
-
public static LimitenInt operator +(LimitenInt x, LimitenInt y)
-
{
-
LimitenInt li = new LimitenInt();
-
li.TheValue = x.TheValue + y.TheValue;
-
return li;
-
}
-
}
-
}
-
-
//调用
-
//1、表达式 2、字面值
-
//234L 长整型 U 无符号整型 UL ; F 浮点型。D double。M decimal,字符字面值 ''
-
//一般的编译器会让相同的字符串字面值共享堆中的同一个内存空间以节约内存
-
-
//3、运算符重载
-
LimitenInt li1 = new LimitenInt();
-
LimitenInt li2 = new LimitenInt();
-
LimitenInt li3 = new LimitenInt();
-
-
li1.TheValue = 10;
-
li2.TheValue = 96;
-
-
li3 = -li1;
-
Console.WriteLine("-{0}={1}", li1.TheValue, li3.TheValue);
-
-
li3 = li1 + li2;//属性值本身有范围限定
-
Console.WriteLine("{0} + {1} = {2}", li1.TheValue, li2.TheValue, li3.TheValue);
-
-
li3 = li1 - li2;
-
Console.WriteLine("{0} - {1} = {2}", li1.TheValue, li2.TheValue, li3.TheValue);
-
-
//4、typeof 运算符
-
//返回为Type类型 使用如下: s.GetType().Name;此方法对所有的类型都有效
-
//打印命名空间所有的字段名与方法名
-
Type t = typeof(Program);
-
FieldInfo[] fi = t.GetFields(); // 字段 集
-
MethodInfo[] mi = t.GetMethods();//方法 集
-
-
foreach (FieldInfo pf in fi)
-
{
-
Console.WriteLine("field:{0}", pf.Name);
-
}
-
-
foreach (MethodInfo m in mi)
-
{
-
Console.WriteLine("Method:{0}", m.Name);
-
}
第九章 语句
//switch 语句段中,必须以一个跳转语句结尾,这和C/C++不同。
//跳转语句包括:break;goto;return;continue;throw等。
//using 语句:首先介绍资源,包括分配资源,使用资源,处置资源
第十章 结构
-
//1、结构是值类型,隐式密封,sealed,不能被派生。 但是,声明的时候需要加修饰符。比如public,默认为private。
-
//2、结构的内存排列在栈中。其类型变量不能为null。
-
//3、结构vs类 1)类是引用类型 2)结构是隐式密封,不能被派生
-
-
CSimple cs1 = new CSimple(),cs2;//类实例 (在堆中分配了空间)
-
Simple ss1 = new Simple(),ss2 = new Simple();//结构实例 (没有在堆中分配空间)
-
//这里需要注意一个问题,我们也可以不使用new运算符创建结构的实例
-
//但是我们必须显式的设置所有的数据成员之后,才可以使用它们的值和函数成员
-
cs1.x = ss1.x = 3;
-
cs1.y = ss1.y = 5;
-
-
cs2 = cs1;//赋值类实例 (赋值之后,两个类的引用指向堆中同一块空间)
-
ss2 = ss1;//赋值结构实例 (赋值之后,两个结构变量值相等。此变量在栈中)
-
-
//4、结构可以有实例构造函数(必须有参)和静态构造函数,但不允许有析构函数
-
//5、要想把一个结构实例作为引用类型对象,必须创建装箱操作。
第十一章 枚举
-
[Flags]
-
enum CardDeckSetting : uint
-
{
-
SingleDeck = 0x01, //位0
-
LargePictures = 0x02, //位1
-
FancyNumbers = 0x04, //位2
-
Animation = 0x08 //位3
-
}
-
enum TrafficLight : byte
-
{
-
Green = 1,
-
Yellow = 10,
-
Red = 30
-
}
-
#region 枚举类型 定义在class外面,这样可以被其他class调用
-
-
enum Color
-
{
-
Red = 1, // 中间用 逗号
-
Blue = 2,
-
Green = 3
-
}
-
#endregion
-
-
class MyClass
-
{
-
bool UseSingDeck = false,
-
UseBigPictures = false,
-
UseFancyNumbers = false,
-
UseAnimation = false,
-
UseAnimationAndFancyNumbers = false;
-
public void SetOptions(CardDeckSetting ops)
-
{
-
UseSingDeck = ops.HasFlag(CardDeckSetting.SingleDeck);
-
UseBigPictures = ops.HasFlag(CardDeckSetting.LargePictures);
-
UseFancyNumbers = ops.HasFlag(CardDeckSetting.FancyNumbers);
-
UseAnimation = ops.HasFlag(CardDeckSetting.Animation);
-
// UseAnimationAndFancyNumbers = ops.HasFlag(CardDeckSetting.Animation | CardDeckSetting.FancyNumbers);
-
//上句可以改写为
-
CardDeckSetting testFlags = CardDeckSetting.Animation | CardDeckSetting.FancyNumbers;
-
UseAnimationAndFancyNumbers = ops.HasFlag(testFlags);
-
}
-
-
public void PrintOptions()
-
{
-
Console.WriteLine("Options Setting :");
-
Console.WriteLine("Use Single Deck - {0}", UseSingDeck);
-
Console.WriteLine("Use Big Pictures - {0}", UseBigPictures);
-
Console.WriteLine("Use Fancy Numbers - {0}", UseFancyNumbers);
-
Console.WriteLine("Use Animation - {0}", UseAnimation);
-
Console.WriteLine("Use Animation and FancyNumbers - {0}", UseAnimationAndFancyNumbers);
-
-
}
-
public int val = 20;
-
public void ListInts(params int[] inVals)
-
{
-
if (inVals != null && inVals.Length != 0)
-
{
-
foreach (int i in inVals)
-
{
-
//i *= 10;//迭代变量只能输出,无法赋值,赋值用for语句。
-
Console.WriteLine("{0}", i);
-
}
-
}
-
}
-
-
public int Cal(int a, int b, int c)
-
{
-
return a * b * c;
-
}
-
public int Cal1(int a, int b, int c = 9) //可选参数,填入默认值
-
{
-
return a * b * c;
-
}
-
}
第十二章 数组
数组的结构,其本身是一个引用类型。
数组是引用类型与C++有很大区别,C#中数组的维度是在实例化后才会被确定的,所以,我们申明的时候,一般都不加数字进去。
类似: int[] aa = new int[4];
矩形数组初始化:
交错数组初始化:
数组是从system.array类当中继承而来,有一些个方法可以应用。
比如下面的Clone方法:
对于克隆值类型与克隆引用类型效果不一样。如下图所示:
比较数组类型
-
//1、元素 维度 维度的长度 数组长度=维度*维度的长度
-
//2、数组的类型:矩形数组(类似矩阵) 交错数组(行矩阵长度不等)
-
//3、数组是对象,是引用类型。引用在堆或者栈上
-
// 尽管数组是引用类型,但是其元素可以是值类型(栈和堆中)或者是引用类型。(都在堆中)
-
//4、矩形数组与一维数组
-
// 注意:不可以在声明数组的时候,把维度的长度加进去,逗号(维度)是类型的一部分,维度的长度不是。
-
// 方括号在基类后,而不在变量名称后。数组声明后,其维度数就确定了,维度长度在数组实例化后确定。
-
int[] arr2 = new int[4];//数值型数组
-
MyClass[] mcArr = new MyClass[4];//引用型数组,没有()括号。
-
-
int[] myIntArray;//声明数组
-
myIntArray = new int[4];//实例化数组
-
for (int i = 0; i < 4; ++i)//赋值并打印
-
{
-
myIntArray[i] = i*10;
-
Console.WriteLine("Value of element {0} = {1}",i,myIntArray[i]);
-
}
-
//数组的初始化 , 省略 new int[] 依然可以说明。一般最后一个维度可以认为是元素个数
-
int[] arrayF = new int[3] { 10, 20, 30 };
-
int[] arrayS = { 10,20,30};
-
-
int[,] arrayT = new int[2, 3] { { 0, 1, 2 }, { 10, 20, 30 } };
-
int[,] arrayFO = {{0,1},{2,3}};
-
//当然,数组也支持初始化一个隐式类型的数组
-
var arr = new [,] {{0,1},{2,3}};
-
-
//5、交错数组
-
//简单理解为数组的数组,其子数组的个数可以不同,注,不能在声明语句中初始化顶层数组之外的数组
-
// int[][] jagArr = new int[3][4];//eeor
-
int[][] jagArr = new int[3][];//这样可以,初始化顶层数组。其本身有四个对象。
-
//交错数组的初始化不能在一个步骤中完成,其本身是每个数组独立创建完成的。
-
//步骤:1、 实例化顶层数组 2、分别实例化每一个子数组
-
jagArr[0] = new int[] { 10, 20 };
-
jagArr[1] = new int[] { 20, 30 };
-
jagArr[2] = new int[] { 30, 40 };
-
-
//混合体,交错数组中,可能存在矩形数组。
-
int[][,] ARR = new int[3][,];//声明并实例化带有3个二维数组的交错数组
-
ARR[0] = new int[,] {{1,2},{3,4}};
-
//打印是: ARR.GetLength(0) ARR[i].GetLength(0) ARR[i].GetLength(1) 循环控制的长度
-
//在foreach 控制语句中,item(迭代变量是只读的)。但对于引用类型数组来说,却不一样
-
//我们虽然无法改变引用,但我们可以通过迭代变量的属性来改变数据的值。前提是必须是已经存在的对象。
-
Array[] mcArray = new Array[4];//创建数组
-
for (int i = 0; i < 4; ++i)
-
{
-
mcArray[i] = new Array(); //创建类对象
-
mcArray[i].MyField = i;//设置字段
-
}
-
foreach(Array item in mcArray)
-
{
-
item.MyField += 10;
-
}
-
foreach(Array item in mcArray)
-
{
-
Console.WriteLine("{0}", item.MyField);
-
}
-
-
//6、数组协变,即使某个对象不是数组的基类型,我们也可以把它赋值给数组元素
-
//7、C#数组从system.array类继承而来,继承了基类的很多有用的属性和方法
-
// Rank/Length/GetLength/Clear/Sort/BinarySearch/Clone/IndexOf/Reverse/GetUpperBound
-
int[] array99 = new int[] { 12, 13, 90, 98, 43, 67 };
-
//Array.Sort(array99);
-
//Array.Reverse(array99);
-
//8、Clone方法
-
//克隆值类型会产生两个独立的数组
-
//克隆引用类型会产生指向相同对象的两个数组
-
//Clone方法返回Object类型的引用,它必须被强制转换成数组类型
-
int[] IntArray = new int[] { 1,2,3};
-
int[] IntArray2 = (int[])IntArray.Clone();//强制转换,浅复制,复制元素
-
IntArray2[0] = 100;//IntArray 的值也随之改变
-
IntArray2[1] = 200;//这些值都是在堆中
-
IntArray2[2] = 300;