您的位置:首页 > 编程语言 > C#

My C# Study Notes

2015-08-04 10:47 267 查看
一.使用Check关键字,包装在Check关键字域内时,C#编译器会使用额外的CIL(公共中间语言)来测试两个数值数据类型加减乘除时可能出现的溢出情况。

class Program
{
static void Main(string[] args)
{
//The largest value of byte is 255.
byte b1 = 250;
byte b2 = 6;
try
{
checked
{
byte sum = (byte)AddFun(b1, b2);
}
}
catch (OverflowException e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
static int AddFun(int a, int b)
{
return a + b;
}
}
如果不使用Check关键字,则不会捕获异常。在VS中,属性->生成(Build)->高级,在弹出对话框中选中“检查运算上溢\下溢”,则不用写Check关键字,编译器会自动进行溢出检查,待Release时,取消这个选择就好了。.Net是默认忽略运算溢出的。

二.使用var声明变量只能用于函数内的局部变量,基本类型且必须赋初值(初值不能是NULL),不能用于返回类型的声明,参数或自定义的字段数据。只有在定义LINQ查询返回的数据时才应该使用var关键字,其他任何时候应使用具体类型声明变量,不可滥用var.

三.个C++不同,C#的if...else...判断只能用bool值,不用用-1,0,1这样的值。

四。C#参数修饰符:

如果一个参数没用参数修饰符标记,则认为它是值传递,即被调用的方法收到的是原始数据的拷贝。
out输出参数由被调用方法复制,是引用传递,如果被调用方法没有给输出参数赋值,就会出现编译错误。
ref调用者赋初值,并且可以由被调用者可选地重新赋值,(引用传递)
params允许将一组可变数量的参数作为单独的逻辑参数进行传递,而且必须是方法的最后一个参数。
五.C#支持命名参数,像Objective-C那样在调用函数时指明参数的名字,这种叫命名参数,平常调用参数的方法叫位置参数,命名参数必须写在位置参数的后面。

六.C#中结构体对象是值类型,虽然使用new创建结构体的一个对象,但还是在栈上分配内存,赋值时是值传递。类类型是引用传递,赋值时传递的是对象的引用。默认情况下,当值类型包含其他引用类型时,赋值将产生引用的一个副本,进行的浅拷贝的动作。如果想实现深拷贝,需要实现ICloneable接口。

七.按引用传递引用类型时的规则:

1.如果按引用传递引用类型,被调用者可以改变对象的状态数据的值和引用的对象;

2.如果按值传递引用类型,被调用者可以改变对象的状态数据的值,但不能改变所引用的对象;

八.可空类型:

对值类型后面加一个?表示是一个可空类型,如:

int? nullAbleint = 10;
char? nullAbleChat = 'a';
int?[] nullArray = new int?[10];

string? s = "error" //只能用于值类型
可空类型一般用于数据库查询,因为数据库中有些列的值肯呢个是空的。

??操作符:

int data = GetData() ?? 100;
当GetData()返回空是,将data赋值为100

九.构造函数链:

Constructor():Constructor(string str);

先执行Constructor(string str),在执行Constructor()

十.静态构造函数:

静态构造函数是特殊的构造函数,适用于初始化在编译时未知的静态数据值(如从外部文件读取值或生成随机数等)。

一个类只能有一个静态构造函数,静态构造函数不能被重载;

静态构造函数不溶于访问修饰符且不接受任何参数;

无论创建多少类型对象,静态构造函数只执行一次;

在创建类的实例或首次访问静态成员之前,会先调用静态构造函数;

静态构造函数的执行限于任何实例级别的构造函数;

十一.有关封装:

封装概念的核心是:对象的内部数据不应该从对象实例直接访问。对象数据应该被定义为私有的,如果想改变对象的状态,就要间接使用公共成员。如果将内部数据设置为公共的,就无法知道当前值是否符合系统的当前业务规则。表示对象状态的类成员都不应该标记为公共的。

十二.属性:

C#提供属性方法对私有成员变量进行操作,如:

private string m_strName;
public string name
{
get { return m_strName; }
set
{
if (value.Length > 10)
{
m_strName = value;
}
}
}

属性类似于方法,但是名称后面没有括号,且内部有get, set关键字。其中value表示传进来的变量,随着上下文不同,表示的类型,数据不一样。

可以在类中直接使用属性名进行赋值,简化操作,如在构造函数中:

public Person(String strName)
{
Name = strName;
}
忽略Get或者Set代码块可将属性变为只写或只读属性。C#倾向于使用属性来封装数据。

自动属性:

public string Name { get; set; }
则可以直接对Name进行赋值,获取Name的值。但不容许构建只读或者只写的自动属性。这样做的好处是日后如果逻辑有变化,直接修改这个属性就好了。这是OOP的思想。

对于自定义类型的自动属性返回值,默认的是NULL,如果是内置基本类型,将返回一个安全的默认值。因此如果一个自动熟悉的返回值是自定义类型,它的默认值是NULL,这时候就要在构造函数中对这个自动属性赋值,以确保对象以安全的方式产生。

十三.对象初始化语法:

Person p = new Person("Test") { X = 30, Y = 100};
在创建对象是,可以使用大括号最熟悉进行赋值,这样做是因为不一定所有构造函数都会对所有的字段进行赋值,这种初始化可以保证需要的字段都有合适的默认值。

十四.Const常量:

定义常量是必须初始化,类的const对象默认是static的。

十五.readonly只读字段:

如果一个成员变量在声明时用readonly标记,那么它只能在构造函数中赋值,在其他地方赋值都是非法的。如果一个字段是只读的,要么它在构造函数中赋值。要么它在静态构造函数中赋值,这种情况适用于在运行时才知道值的情况。

十六.如果基类定义可以(担不是必须)由子类重写的方法,就必须使用virtual关键字,如果子类需要改变父类方法的实现细节,就必须使用override关键字。

十七.判断对象是否属于某个类或者接口,使用as,或者is 运算符,如果不是as返回null,然后需要判断对象是否为null,is返回true或者false.

十八.当多个接口有相同的签名的函数和函数名称时,实现这个接口的类可以使用
接口名.方法名 来实现指定的接口的函数,否则所有接口都实现了相同的函数。但这样的实现都是私有的,不能在前面加public修饰符。由于是私用方法,对象级别就不能调用,如果要使用,就需要将对象强制转换为指定接口的类型。


十九.自定义类要实现foreach,就要实现System.Collections下的IEnumerable接口,它其中有GetEnumerator()方法需要实现。GetEnumerator()实际上只是返回一个System.Collections.IEnumertaior的引用。这个接口中有三个方法:bool MoveNext(); ogject Current()(get:); void Reset();方法。

如果自定义类型需要和C#的foreach关键字一起使用,容器就需要定义一个名为GetEnumerator()的方法,它由Ienumerator就扣类型来定制,通常,这个方法的实现只是交给保存子对象的内部成员,然而,我们也可以首页那个yield return语法来提供多个"命名迭代器"方法。

当到达yield return语句后,当前位置被村吃下来,下次调用迭代器会从这个位置开始执行,如:

public IEnumerator GetEnumeraotr()
{
yield retu carArr[0];
yield retu carArr[1];
}


二十.装箱:显示地将值类型分配给System.object变量的过程。当进行装箱操作时,CLR就会在堆上分配新的对象并将值类型的值赋值到那个实例上,因从,返回给我们的就是新分配在堆上的对象的引用。拆箱就是把保存在对象引用中的值转换为栈上相应的值的类型。CLR会验证收到值类型是不是等价于装箱额类型,如果是,就将值赋值回本地栈的变量上。如果不是,将抛出InvalidCastException一场。

装箱和拆箱对导致性能降低,也缺乏类型安装。装箱拆箱过程:

1.必须在托管堆上分配一个新对象。

2.给予栈数据的值必须被转移到新分配的内存的位置。

3.在拆箱时,保存在堆对象中的值必须转移回栈。

4.堆上无用的对象最后被回收。

二十二.如果需要时间深拷贝,就需要实现Clone()方法。

二十三.构建自定义类型的时候,可以实现IComparable已实现该类型的数组可以被排序。实现ComapareTo()方法,决定排序的具体方式。如果要比较两个对象的大小,需要实现ICompare接口,再实现Compare方法。

二十四.装箱:装箱可以定义为显示的将值类型分配给System.Object的过程。如:

Int myInt = 25;

Object oInt = myInt;;

拆箱就是把保存在对象引用中的值转换回栈上的相应值的类型。拆箱必须回到合适的数据类型。

int UnboxInt = (int)oInt ;

当C#编译器发现装箱拆箱语法时,所生成的CIL代码包含box/unbox操作码。如果类型不正确会抛出异常。

274
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: