`

C#学习笔记——面向对象——类的基本概念

 
阅读更多

class MyClass

{

    

}

 

成员

成员的访问修饰符:

public 公有的

protected 受保护的

internal protected 受内部保护的

private 私有的

internal 内部的

 

数据成员 

包括:字段,常量。

 

字段

 

注:C#没有全局变量,所有的变量都是类中的(不同于C++)。

 

声明字段(核心声明)

Type Identifier

 

特性  修饰符  核心声明

说明:

如果一个声明有多个修饰符,它们可以以任何顺序放在核心声明之前。例如public,private,static,const都是修饰符,可以在一起修饰某个声明。

 

 

 

 

字段初始化

Type Identifier=Value;

 

声明多个字段

int x1,x2=12,23;

 

 

 

 

常量

常量声明中必须初始化。

常量在声明后不能改变。

使用const关键字声明:

const Type Identifier=Value;

 

 

 

静态字段

静态字段被类所有实例共享。即所有实例都访问同一内存位置。因此,该内存位置的值是被一个实例改变了,其他对所有的实例都可见。

 

访问静态成员

对象.静态字段

类.静态字段

 

成员常量

与本地常量类似,用于初始化成员常量的值在编译期必须是可计算的,而且通常是一个预定义简单类型或由它们组成的表达式。

不能在成员常量声明以后给它赋值。

 

 

常量就像静态量。实例和类都可以访问常量。

 

与静态量不同的是,常量没有自己的存储位置,而是在编译时被编译器替换。与C/C++的#define类似。

 

注意:static与const不能共用。

 

 

 

 

 

 

 

函数成员

包括:方法,属性,构造函数,析构函数,运算符,索引,事件。

 

 

方法

C#无全局方法

 

方法的声明

任意方法修饰符 返回值类型 方法名 参数列表 函数体

 

调用方法

 

参数

基本概念

形参

 

实参

 

 

值参数

把实参的值复制到形参的参数。

数据通过复制实参的值到形参的方式传递到方法。方法被调用时,系统做如下操作:

在栈中为形参分配空间。

复制实参到形参。

 

引用参数

形参是实参的别名。

使用引用参数时,必须在方法的声明和调用中都使用ref修饰符。

实参必须是变量,在用作实参前必须被赋值。如果是引用类型变量,可以赋值为一个引用或null值。

 

对于值参数

系统在栈中为形参分配新的内存。

 

对于引用参数

不再栈中为形参分配新的内存。

形参的名称相对于实参变量的别名,引用于实参相同的内存地址。

 

 

输出参数

输出参数用于从方法体内把数据传出到调用代码。类似引用参数。

要求:

必须在声明和调用中都是由out修饰符。

实参必须是变量。

在方法内部,输出参数在被读取之前必须被赋值。即输出参数的初始值是无关的,而且没有必要在方法调用之前为实参赋值。

每个输出参数在方法返回之前必须被赋值。

 

参数数组

0个或多个实际参数对应一个特殊的参数。

参数数组:

在一个参数列表中只能有一个参数数组。

如果有,必须是最有一个。

 

声明参数数组

在数据类型前使用params修饰符。

在数组类型后放置一组空的方括号

 

void ListInts(params int[] intVals)

{

}

 

使用参数数组    这种方法调用的形式被称为延伸式

ListInts(10,20);

ListInts(10,20,30);

 

int a=5,b=6,c=7;

ListInts(a,b,c);

 

 

数组变量作实参   

int[] intArray={1,2,3};

ListInts(intArray);

 

 

注意:

值参数的声明和调用都不带修饰符

引用参数和输出参数在声明和调用都使用修饰符。

参数数组声明需要修饰符,调用不需要修饰符。

 

递归

 

方法重载

一个类可以有一个以上的方法拥有相同的名称,这叫做方法重载。

使用相同名称的每个方法必须有一个和其他方法不同的签名。

方法的签名由下列信息组成:

方法的名称。

参数的数目。

参数的数据类型和顺序。

参数的修饰符。

 

 

静态函数成员

如同静态字段,静态函数成员独立于任何类实例。即使没有类的实例,仍然可以调用静态方法。

静态函数成员不能访问实例成员。然而,它们能访问其他静态成员。

 

 

this关键字

在类中使用,是对当前实例的引用。它只能被用在下列类成员的代码块中:

实例构造函数。

实例方法。

属性和索引的实例访问器。

 

不能在任何静态函数的代码中使用this关键字。

 

this被用于下列目的:

用于区分类的成员和本地变量,或参数。

作为调用方法的实参。

 

 

索引

 

索引使用索引运算符,由中括号和中间的索引值构成。

 

索引是一组get set访问器,类似于属性的访问器。

 

例:

string this[int index]

{

    set

    {

        SetAccessorCode

    }

    get

    {

        GetAccessorCode

    }

}

 

 

索引和属性

索引和属性在很多方面是相似的。

和属性一样,索引不用分配内存来存储。

索引和属性都只要被用来访问其他数据成员,这些成员和它们关联,它们为这些成员提供设置和获取访问。

    属性通常访问单独的数据成员。

    索引通常访问多个数据成员。

 

可以把属性想象成提供获取和设置类的多个数据成员的属性。通常提供索引在许多可能的数据成员中进行选择。索引本身可以是任何类型的,不仅仅是数值类型。

 

使用索引时,另外还有一些注意事项如下:

索引可以只有一个访问器,可以有两个。

索引总是实例成员。因此,索引不能被声明为static。

和属性一样,实现set get 访问器的代码不必一定要关联到某个字段或属性。这段代码可以做任何事情或什么不做,只要get访问器返回某个指定类型的值即可。

 

声明索引

索引没有名称。在名称的位置是关键字this。

参数列表在方括号中间。

参数列表中至少必须声明一个参数。

ReturnType this [Type param1,...]

{

    get

    {

        ...

    }

    set

    {

        ...

    }

 

}

 

set访问器

当索引被用于赋值时,set访问器被调用,并被接受两项数据,如下:

一个隐式参数,名称为value,value持有要保存的数据。

一个更多索引参数,表示数据应该保存到哪里。

 

emp[0]="0";

 

 

get访问器

当索引被用于获取值时,get访问器被一个或多个索引参数调用。索引参数指示哪个值将被获取。

string s=emp[0];

 

例:

class Employee

{

    public string LastName;

    public string FirstName;

    public string CityOfBirth;

 

    public string this[int index]

    {

        set

        {

            switch(index)

            {

                case 0:LastName=value;

                break;

 

                case 1: FirstName =value;

                break;

 

                case 2: CityOfBirth =value;

                break;

 

                default:

                   throw new ArgumentOutRangeException("index");

                   break;

 

 

 

            }

        }

 

        get

 

        {

            switch(index)

            {

                case 0:return LastName;

 

                case 1:return   FirstName;

                break;

 

                case 2:return   CityOfBirth;

                break;

 

                default:

                   throw new ArgumentOutRangeException("index");

                   break;

 

 

 

            }

        }

 

 

 

    }

 

}

 

 

索引重载

只要索引的参数列表不同,类可以有多个索引。被称为索引重载。

重载的索引必须有不同的参数列表。

class MyClass

{

    public string this[int index]

    {

        get{}

        set{}

    }

 

    public string this[int index1,int index2]

    {

        get{}

        set{}

    }

 

    public string this[float index]

    {

        get{}

        set{}

    }

 

 

 

}

 

 

 

实例化类

new ClassName();

 

 

构造函数(构造器)

构造函数用于初始化类实例的状态。

如果希望能从类的外部创建类的实例,需要声明构造函数为public。

 

构造函数的名称和类名相同。

构造函数不能有返回值。

 

 

默认构造函数

如果在类的声明中没有显示地提供实例构造函数,那么编译器会提供一个隐式的默认构造函数:

不带参数。

方法体为空。

 

如果定义了一个或多个构造函数,那么编译器将不会为该类定义默认构造函数。

至少有一个显示定义的构造函数,编译器不会创建任何附加的构造函数。

在Main中,试图使用不带参数的构造函数创建新的实例。因为没有零参数的构造函数,所以编译器会产生一个错误信息。

 

静态构造函数

static构造函数初始化类层次的项目。通常静态构造函数初始化类的静态字段。

 

类的层次的项目需要被初始化:

在任何静态成员被引用之前。

在类的任何实例被创建之前。

 

静态构造函数在下列方面就像实例构造函数:

静态构造函数的名称必须和类名相同。

构造函数不能返回值。

 

静态构造函数在下列方面和实例构造函数不同:

静态构造函数声明中使用static关键字。

类只能有一个静态构造函数,而且不能带参数。

静态构造函数不能有访问修饰符。

 

关于静态构造函数应该了解的其他重要内容如下:

类即可以有静态构造函数,也可以有实例构造函数。

如同静态方法,静态构造函数不能访问所在类的实例成员,因此也不能使用this访问器。

不能从程序中显示调用静态构造函数,它们被系统自动调用。

    在类的任何实例被创建之前。

    在类的任何静态成员被引用之前。

 

 

构造函数的可访问性

构造函数可以为public,private等等。

 

 

class MyClass

{

    public MyClass()

{

 

}

}

 

私有构造函数

class MyClass

{

    private MyClass()

{

 

}

}

 

 

构造函数支持重载

 

 

对象初始化列表

对象初始化列表允许在创建新的对象实例时设置字段和属性的值。

对象初始化列表扩展了创建语法,在表达式的尾部放置了一组成员初始化列表。该语法有两种形式:

一种形式包括构造函数的参数列表。

一种不包括。

 

new TypeName(ArgList){FieldOrProp=InitExpr,FieldOrProp=InitExpr,...}

new TypeName  {FieldOrProp=InitExpr,FieldOrProp=InitExpr,...}

 

关于对象初始化列表的重要内容如下:

被初始化的成员在创建对象的代码中必须是可访问的(如public)。

初始化在构造函数完成之后发生。

 

例:

public class Point

{

    public int X=1;

    public int Y=2;

}

 

static void Main()

{

    Point pt1=new Point();

    Point pt2=new Point    {X=5,Y=6}

    Console.WriteLine("pt1:{0},{1}",pt1.X,pt1.Y);

    Console.WriteLine("pt2:{0},{1}",pt2.X,pt2.Y);

}

 

 

析构函数

垃圾回收时,执行析构函数中的代码。执行析构函数将隐士调用基类的析构函数。

class MyClass

{

    ~MyClass()

{

 

}

}

 

 

 

类成员

访问修饰符

public

private

internal   成员只能有定义它的程序集(项目)内部的代码访问

protected

 

 

定义字段

class MyClass:MyBaseClass

{

public int MyInt;

}

 

readonly修饰符

字段修饰符。类似于const字段,一旦被设定就不能改变。

const字段只能在字段的声明语句中初始化,而readonly字段可以在下列任意位置设置它的值:

字段声明语句,如同const。

类的任何构造函数。如果是static字段。初始化必须在static构造函数中完成。

 

const字段的值必须在编译期决定,而readonly字段的值可以在运行期决定。这种增加的自由性允许你在不同构造函数中设置不同的值!

 

和const不同,const总是像静态的,而readonly字段:

它可以是实例字段,也可以是静态字段。

它在内存中存储位置。

 

 

readonly  字段只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值。

class MyClass:MyBaseClass

{

public readonly int MyInt;

}

 

静态字段 static   字段只能通过类访问,不能通过对象实例来访问。

class MyClass:MyBaseClass

{

public static int MyInt;

}

 

 

virtual  方法可以重写

abstract 方法必须在非抽象的派生类中重写(只用于抽象类)。

override 方法重写了一个基类方法(如果方法被重写,就必须使用该关键字)。

extern  方法定义放在其他地方。

 

 

使用了overrid,也可以使用sealed指定在派生类中不能对这个方法作进一步修改。即这个方法不能有派生类重写。

 

 

属性

使用属性看起来就像写入或读取一个字段,语法是相同的。

对象.属性名称

对象.属性名称=值

 

属性是一个函数成员:

属性不为数据存储分配内存。

属性执行代码

 

属性是指蚁族两个匹配的、称为访问器的方法。

set访问器用于为属性赋值。

get访问器用于从属性获取值。

 

 

属性声明

属性的作用:对访问对象成员值做控制或限制。

使用get set 关键字定义

格式:

属性类型  属性名

{

    set

    {

        CodeToSetPropertyValue

    } 

 

    get

    {

        CodeToGetPropertyValue

        return 属性类型的Value

    }

 

}

 

 

set访问器总是:

一个单独的,隐式的值参,名称为value,与属性的类型相同。

一个返回类型void。

 

get访问器总是:

没有参数。

一个与属性类型相同的返回类型。

get访问器必须包含return语句。

 

访问其set,get可以任何顺序声明。

 

注意:

属性本身没有任何存储。

访问器决定如何处理发进来的数据,以及什么数据应被发送出去。

 

通常情况下,属性使用一个字段来进行存储。

set访问器中,把输入参数value赋值给字段。

get访问器中,返回该字段的值。

 

访问器是隐式调用的。不可以显示的用set(value) get()调用。

 

 

属性和关联字段

类的字段建议声明为private,属性建议声明为public。

 

和属性相关联的字段常被称为后备字段或后备存储。

 

命名约定:

约定一:

关联字段使用Camel大小写。

属性使用Pascal大小写。

两者在不考虑大小写的情况下,应该是一样的。

 

约定二:

属性使用Pascal大小写。

字段使用Camel大小写版的相同标识符,并以下划线开始。

 

private int firstField;

public int FirstField

{

    get{return firstField;}

    set{firstField=value;}

}

 

 

private int _secondField;

public int SecondField

{

    get{return  _secondField ;}

    set{ _secondField =value;}

}

 

 

执行其他计算

属性不局限于仅仅关联的后备字段传出数据。

 

 

只读属性和只写属性

可以忽略其中一个块创建只读或只写属性

 

只有get访问器的属性称为只读属性。

只有set访问器的属性称为只写属性。

两个访问器至少有一个必须定义。

 

 

类中的其他代码可以访问这些代码块中的数据

 

public class MyClass

{

    public readonly string Name;

    private int intVal;

    public int Val

    {

        get

        {

            return intVal;

}

 

set

{

    if(value>=0 && value<=10)

{

    intVal=value;

}

 

}

}

 

 

}

 

使用

MyClass myobj=new MyClass("My Object");

int i=10;

myobj.Val=i;    //set

Console.WriteLine("Value {0} assigned to myobj.Val",myobj.i);    //get

 

 

 

自动实现属性

C# 3.0增加了自动实现属性,允许只声明属性而不声明后备字段。

自动实现属性的要点如下:

不声明后备字段——编译器根据属性的类型分配存储。

不能提供访问器的方法体——它们被简单地声明为分号。get担当简单的读,set担当简单的写。 

除非通过访问器,否则不能访问后备字段。因为不能用其他方法访问它,所有只读和只写自动属性没有意义,不被允许

class C1

{                                   //没有声明后备字段

    public int MyValue     //分配内存

    {

        set; get;       //访问器的方法被声明为分号

    }

}

 

静态属性

属性可以被声明为static。静态属性的访问器与所有静态成员一样:

不能访问类的实例成员。能被实例成员访问。

存在,不管类是否有实例。

当从类的外部访问时,必需使用类名引用,而不是实例名。

 

 

访问器的访问修饰符

属性和索引都带有get set访问器。默认情况下,成员的两个访问器有和成员自身相同的访问级别。也即若一个属性有public访问级别,则它的访问器有同样的访问级别,对索引也一样。

特定情况下,成员访问器可以有不同的访问级别。

例:

class MyClass

{

    private string string_name="John Doe";

    public string Name

    {

        get { return _Name;}

        protected set {_Name=value;}

    }

}

 

访问器的修饰符有以下限制:

仅当成员(属性或索引)既有get又有set访问器,其访问器才能有访问修饰符。

虽然两个访问器必须出现,但它们中只能有一个有访问修饰符。

访问器的访问修饰符必须比成员的访问级别有更严格的限制。

 

 

 

部类和分布类型

类的声明可以被分割成几个分部类的声明

每个分部类的声明都含有一些类成员的声明。

类的分部类声明可以在同一个文件中也可以在不同文件中。

 

 

每个局部类必须被标为partial class。分部类声明起来和普通类声明相同。

 

 

类型修饰符partial不是关键字,所以不在其他上下文中,可以在程序中把它作为标识符。但直接用在关键字class,struts或interface之前时,它表示分部类型。

 

组成类的所有分部类必须在一起编译。使用分布类声明的类必须有相同的含义,如同它所有类成员都被声明在一个单独的类声明体内。

除了类,还可以创建两种分部类型:

局部结构

局部接口

 

 

 

分部方法

分部方法是分部类中声明在两个部分中的方法。分部方法的那两个部分可以声明在分部类的不同部分,也可以声明在同一部分。

分部方法的两个部分如下:

定义声明给出签名和返回类型,声明的实现部分只是一个分号。

实现声明给出签名、返回类型,还有正常形式的语句块实现。

 

关于分部方法需要了解的重要内容如下:

在定义声明和实现声明中都必须包含上下文关键字partial。直接放在void之前。

签名不能包括访问修饰符,这使部分方法是隐式私有的。

返回类型必须是void。

参数列表不能包含out参数。

 

可以有定义部分而没有实现部分。这种情况下,编译器把方法的声明部分以及方法内部任何对方法的调用都移除。然而,如果类有分布方法的实现方法,它也必须有定义部分。

 

例:

partial class MyClass

{

    partial void PrintSum(int x,int y);

    public void Add(int x,int y)

    {

        PrintSum(x,y);

    }

}

 

 

partial class MyClass

{

    partial void PrintSum(int x,int y)

    {

        Console.WriteLine("Sum is {0}",x+y);

    }

 

}

 

class Program

{

    static void main()

    {

        var mc=new MyClass();

        mc.Add(5,6);

    }

 

}

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics