黑马程序员:C#基础篇(一)

来源:互联网 发布:hr面试java常问的问题 编辑:程序博客网 时间:2024/06/05 11:28

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

.net Framework

.net Framework提供了“公共语言运行规范”和基本类库来支撑面向服务的整合应用,.net框架如图1-1所示。

                                                     图1-1 .net框架

其中两个主要组件是公共语言运行库(CLR)和.net framework类库(FCL)。CLR可以看作是一个程序执行时管理代码的代理,提供内存管理、线程管理和远程管理等核心服务,并且强制实施类型安全,以其为目标的代码称为“托管代码”。FCL是一个面向对象的可重用类型集合。

.net 是多语言支持的,不管用何种语言开发,只要是CLR支持的,最终都会通过编译器(如csc)将源代码编译成MSIL并生成所需的元数据。元数据其实就是程序集的一种自我介绍,它包括代码中的类型信息,包括每种类型的定义、成员签名、引用的成员和托管代码执行时所使用的其他数据。生成的MSIL和元数据包含在一个可移植可执行的PE文件中。要运行MSIL,必须先通过JIT(即时编译器)将其转换成本机代码。JIT编译考虑到执行过程中有些代码可能永远不会被调用,所以不是耗费时间和内存将PE文件中的所有MSIL转换成本机代码,而是根据需要转换MSIL并存储以供后续的调用使用。

C#基础

1、数据类型

C#常见的值类型和引用类型如图2-1所示。

                                                              图2-1 常见数据类型

1.1类型转换

C#中存在一些预定义的转换,如int-->long。转换可以分为隐式转换(implicit conversions)和显式转换(explicit conversions)。隐式类型转换必须是类型兼容的。

(1)隐式数值类型的转换

sbyte -->short、int、long、float、double、decimal

byte   -->short、ushort、int、uint、long、ulong、float、double、decimal

short  -->int、long、float、double、decimal

ushort-->int、uint、long、ulong、float、double、decimal

int      -->long、float、double、decimal

uint    -->long、ulong、float、double、decimal

long   -->float、double、decimal

ulong -->float、double、decimal

float   -->double

char   -->ushort、int、uint、long、ulong、float、double、decimal

其中从整形到浮点型的转换可能会导致精度的下降。对比于值类型的范围,我们可以看到隐式值类型转换其实就是从低精度到高精度的转换。

(2)隐式枚举转换

隐式枚举转换允许把十进制整数0转换成任何枚举类型,但是其他整数则不存在这种转换。

(3)隐式引用转换

隐式引用转换包含常说的里氏转换,子类可以直接转换成父类,包含接口的继承。

数组的转换,数组的维数必须相同,数组中存的元素必须是引用类型并且存在隐式引用转换。

(4)显式数值类型转换

显式数值类型转换值从一种数字类型到另一种数字类型之间不能通过隐式类型转换实现的转换,可以看作从大到小的转换。显式数值转换可能会造成信息的损失或者异常。

(5)显式引用类型的转换

指向子类对象的父类可以强制转换成子类

(6)用户自定义转换

用户自定义转换必须为静态的,语法:static 访问修辞符 转换修辞符 operator 转换类型(参数)

class A    {        public int value;        public A(int value)        { this.value = value; }        //自定义从B类型到A类型的隐式转换        static public implicit operator A(B b)        { return new A(b.value); }        //定义int到A类型的隐式转换        static public implicit operator A(int value)        { return new A(value); }        //定义A类型到int的显式转换        static public explicit operator int(A a)        { return a.value; }        //定义A类型到string的隐式转换        static public implicit operator string(A a)        { return "this class value is " + a.value; }    }    struct B    {        public int value;        public B(int value)        { this.value = value; }        //定义int到B类型的隐式转换        static public implicit operator B(int value)        { return new B(value); }        //定义B类型到int的显式转换        static public explicit operator int(B b)        { return b.value; }        //定义B类型到string的显式转换        static public explicit operator string(B b)        { return "this struct value is " + b.value; }    }    class Program    {        static void Main(string[] args)        {            B b = new B();            A a = b;            a = 10;            b = a.value;            Console.WriteLine(a+";"+(string)b);            Console.ReadKey();        }    }

1.2溢出机制,CHecked与Unchecked

多种基元类型的算术运算都会导致结果溢出,例如:

Byte b = 100;b = (Byte) (b + 157);//结果为1


大多数情况下,如果未检测到这种溢出,往往会产生一些意想不到的结果,溢出检查默认是关闭的,可以通过Checked开启溢出检查。

byte b = 100;b = checked((byte)(b + 157));//抛出OverflowException异常


还可以通过checked语句来检查语句块中的溢出。

checked{      byte b = 100;      b += 157; //抛出OverflowException异常}

1.3值类型与引用类型

引用类型总是从托管堆上分配,C#中的new操作符返回对象位于托管堆中的内存地址。

使用引用类型时,(1)内存必须从托管堆中分配(2)每个托管堆中分配的对象都有一些与之关联的附加的成员必须被初始化(3)从托管堆中分配对象可能会导致执行垃圾收集。

值类型则通常分配在线程的堆栈上,表示值类型实例的变量不包含指向实例的指针,操作时无需解析其引用;值类型不受GC的控制,减小了托管堆得压力。

        class Ref { public int x;}        struct Val { public int x;}        static void Fun()        {            Ref r1 = new Ref();//分配在托管堆上            Val v1 = new Val();//分配在堆栈上            r1.x = 1;//解析指针            v1.x = 1;//直接在堆栈上修改            Console.WriteLine(r1.x);            Console.WriteLine(v1.x);            Ref r2 = r1;//复制引用            Val v2 = v1;//在堆栈上分配,然后复制成员            r1.x = 5;//r1.x与r2.x都改变了            v1.x = 6;//改变了v1.x,没有改变v2.x            Console.WriteLine(r1.x);            Console.WriteLine(r2.x);            Console.WriteLine(v1.x);            Console.WriteLine(v2.x);        }

使用ref和out关键字传递参数,可以使参数按引用传递。out用于把参数传出方法体外,参数在外界可以不用赋值。

        static void Change(ref int[] arr)        {            arr[0] = 110;            arr = new int[] { 1, 2, 3, 4, 5 };            Console.WriteLine(arr[0]);        }        static void Main()        {            int[] arr = { -1, -3, -5 };            Console.WriteLine(arr[0]);//输出为-1            Change(ref arr);//输出1            Console.WriteLine(arr[0]);//输出1            Console.ReadKey();        }

Change方法中arr数组的所有改变都影响Main方法中的原始数组,但是使用new关键字重新分配了一个原始数组,因此调用Change后,对arr的任何引用均指向Change方法中创建的5个元素的数组。

1.4值类型的装箱和拆箱

装箱和拆箱使值类型可以被视为对象使用。

int i = 888;object o = (object) i ; //装箱o = 123;i = (int) o ; //拆箱,相对于简单的赋值而言,装箱必须分配并构造一个全新的对象,拆箱需要进行强制转换,这些都是影响性能的因素。

2、结构、枚举和类

2.1结构

结构与类几乎共享所有的语法,但是结构比类受到的限制更多。

(1)结构是值类型,而类是引用类型。

(2)与类不同,结构的实例化可以不使用new运算符。

(3)结构不能声明无参构造函数和析构函数,结构的副本由编译器自动生成和销毁,因此不需要。

(4)结构不能继承类和结构,也不能被继承,所有结构直接继承自System.ValueType。

(5)但是结构可以实现接口。

(6)不能在结构中初始化实例字段,但是其静态字段可以初始化。

结构适合于表示一些轻量级对象。如Point、Rectangle、Color等。

    public struct Rectangle    {        public int width, height;        public Rectangle(int width,int height)        { this.width = width; this.height = height; }    }

2.2枚举

枚举实际上是为一组逻辑上密不可分的整数值提供便于记忆的符号。结构是由不同类型的数据组成的一组新的数据结构,结构变量的值由各个成员的值组合而成,而枚举变量某一时刻只能取枚举中一个元素的值。

当没有给枚举中元素赋值时,系统默认枚举中每一个元素类型都是int型,且第一个元素为0,后面依次递增。

也可以直接为枚举中的元素直接赋值,赋值的类型限于short、int、long、byte等整数类型。

    public enum WeekDay    {         Sunday=0,Monday=1,Tuesday,Wednesday,Thursday,Friday,Saturday    }

2.3类

类与结构不同,类支持单继承,继承也是面向对象的基础(接口支持多继承);类可以定义在不同的源文件中,需要用到关键字partial。类还可以定义为静态的,抽象的。
类具有表示其数据和行为的如下成员:

(1)字段:被视为类的一部分的对象实例,通常用于保存数据。

(2)属性:属性是一种特殊的方法,可以为字段提供保护和扩展性。

(3)方法:方法定义类可以执行的操作。

(4)事件:事件其实就是委托变量,当某一事件发生时,通过委托来触发。

(5)运算符:运算符是对操作数执行运算的符号,可以重新定义(运算符的重载)。

(6)索引器:索引器允许类以类似数组的方式为对象建立索引。

(7)构造函数:特殊的方法,第一次创建对象时调用。

(8)析构函数:析构函数是当对象即将从内存中移除时由公共语言运行库执行引擎调用的方法,通常用来进行资源的释放。

(9)嵌套类型:在类或结构中声明的类型。

2.4访问级别

用于控制访问权限的修饰符:

(1)private:表示定义的成员是私有的,只能在内部访问。

(2)protected:受保护的,只能在当前类型或者派生类型中访问。

(3)internal :只能在当前程序集中访问。

(4)public:表示定义的成员是公开的。

(5)protected+internal:取二者的交集,只能在当前程序集中的当前类或派生类中访问。
2.4.1类和结构的可访问性

没有嵌套在其他类或结构中的类和结构可以是公共的或者内部的,加public声明为公共的可由任何其他类型访问,声明为内部的只能由同一程序集中的类型访问(默认声明为内部的,可以加internal显式声明)。类和结构始终能够访问自身及其所有成员。

2.4.2类成员和结构成员的可访问性

可以使用上面5种访问类型之一来声明类成员或者结构成员,这里就不赘述了。

2.4.3其他类型

接口也可以声明为公共类型或者内部类型,但与类不同,接口的成员始终是公共的,不能应用任何访问修饰符。

命名空间和枚举成员始终是公共的,不能应用访问修饰符。枚举和委托类型可以是公共的也可以是内部的,默认具有内部访问级别。

 

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

原创粉丝点击