类成员

 类中的数据和函数称为类的成员。除了这些成员外,类还可以包含嵌套的类型(例如其他类)。类中的所有成员都可以声明为public(此时可以在类的外部直接访问它们)或private(此时,它们只能由类中的其他代码来访问)。C#中protected(表示成员仅能由该成员所在的类及其派生类访问)

数据成员

数据成员包含了类的数据-- 字段、常量和事件。数据成员可以是静态数据(与整个类相关)或实例数据(类的每个实例都有它自己的数据副本)。通常,对于面向对象的语言,类成员总是实例成员,除非用static进行了显式的声明

一旦实例化Customer对象,就可以使用语法Object.FieldName来访问这些字段:

 Customer Customer1 = new Customer();

 Customer1 .FirstName = "JIM";

常量与类的关联方式同变量与类的关联方式一样。使用const关键字来声明常量。如果它们声明为public,就可以在类的外部访问

事件是类的成员,在发生某些行为(例如改变类的字段或属性,或者进行了某种形式的用户交互操作)时,它可以让对象通知调用程序。客户可以包含所谓"事件处理程序"的代码来响应该事件。

函数成员

函数成员提供了操作类中数据的某些功能,包括方法、属性、构造函数和终结器(finalizer)、运算符以及索引器。

方法是与某个类相关的函数,它们可以是实例方法,也可以是静态方法。实例方法处理类的某个实例,静态方法提供了更一般的功能,不需要实例化一个类.

属性是可以在客户机上访问的函数组,其访问方式与访问类的公共字段类似。C#为读写类上的属性提供了专用语法,所以不必使用那些名称中嵌有Get或Set的偷工减料的方法。因为属性的这种语法不同于一般函数的语法,在客户代码中,虚拟的对象被当做实际的东西。

构造函数是在实例化对象时自动调用的函数。它们必须与所属的类同名,且不能有返回类型。构造函数用于初始化字段的值。

终结器类似于构造函数,但是在CLR检测到不再需要某个对象时调用。它们的名称与类相同,但前面有一个~符号。

运算符执行的最简单的操作就是+和-。在对两个整数进行相加操作时,严格地说,就是对整数使用+运算符。C#还允许指定把已有的运算符应用于自己的类(运算符重载)

索引器允许对象以数组或集合的方式进行索引

1. 方法

在C#中,每个函数都必须与类或结构相关

正式的C#术语实际上区分了函数和方法。在这个术语中,"函数成员"不仅包含方法,而且也包含类或结构的一些非数据成员,例如索引器、运算符、构造函数和析构函数等,甚至还有属性。这些都不是数据成员,字段、常量和事件才是数据成员

方法的声明

在C#中,定义方法的语法与C风格的语言相同,与C++和Java中的语法也相同。与C++的主要语法区别是,在C#中,每个方法都单独声明为public或private,不能使用public:块把几个方法定义组合起来。另外,所有的C#方法都在类定义中声明和定义。在C#中,不能像在C++中那样把方法的实现代码分隔开来。

[modifiers] return_type MethodName([parameters])
{
// Method body
}

每个参数都包括参数的类型名及在方法体中的引用名称。但如果方法有返回值,return语句就必须与返回值一起使用,以指定出口点

public bool IsSquare(Rectangle rect)
{
return (rect.Height == rect.Width);
}

如果方法没有返回值,就把返回类型指定为void,因为不能省略返回类型。如果方法不带参数,仍需要在方法名的后面写上一对空的圆括号()

(2) 调用方法

C#中调用方法的语法与C++和Java中的一样,C#和Visual Basic的唯一区别是在C#中调用方法时,必须使用圆括号,这要比Visual Basic 6中有时需要括号,有时不需要括号的规则简单一些

(3) 给方法传递参数

参数可以通过引用或值传递给方法。在变量通过引用传递给方法时,被调用的方法得到的就是这个变量,所以在方法内部对变量进行的任何改变在方法退出后仍旧发挥作用。

而如果变量是通过值传送给方法的,被调用的方法得

到的是变量的一个副本,也就是说,在方法退出后,对变量进行的修改会丢失。对于复杂的数据类型,按引用传递的效率更高,因为在按值传递时,必须复制大量的数据。

using System;

namespace Wrox.ProCSharp. ParameterTestSample
{
class ParameterTest
{
static void SomeFunction(int[] ints, int i)
{
ints[0] = 100;
i = 100;
}

public static int Main()
{
int i = 0;
int[] ints = { 0, 1, 2, 4, 8 };
// Display the original values
Console.WriteLine("i = " + i);
Console.WriteLine("ints[0] = " + ints[0]);
Console.WriteLine("Calling SomeFunction...");

         // After this method returns, ints will be changed,
// but i will not
SomeFunction(ints, i);
Console.WriteLine("i = " + i);
Console.WriteLine("ints[0] = " + ints[0]);
return 0;
}
}
}

结果是

i = 0
ints[0] = 0
Calling SomeFunction...
i = 0
ints[0] = 100

注意字符串是不同的,因为字符串是不能改变的(如果改变字符串的值,就会创建一个全新的字符串),所以字符串无法采用一般引用类型的行为方式。在方法调用中,对字符串所作的任何改变都不会影响原来的字符串

(4) ref参数

通过值传送变量是默认的,也可以迫使值参数通过引用传送给方法。为此,要使用ref关键字。如果把一个参数传递给方法,且这个方法的输入参数前带有ref关键字,则该方法对变量所作的任何改变都会影响原来对象的值

static void SomeFunction(int[] ints, ref int i)
{
ints[0] = 100;
i = 100;       

}

在调用该方法时,还需要添加ref关键字

SomeFunction(ints, ref i);

最后,C#仍要求对传递给方法的参数进行初始化,理解这一点也是非常重要的。在传递给方法之前,无论是按值传递,还是按引用传递,变量都必须初始化。

(5) out关键字

编译器使用out关键字来初始化。在方法的输入参数前面加上out关键字时,传递给该方法的变量可以不初始化。该变量通过引用传送,所以在从被调用的方法中返回时,方法对该变量进行的任何改变都会保留下来。在调用该方法时,还需要使用out关键字,与在定义该方法时一样:

static void SomeFunction(out int i)
{
i = 100;
}

public static int Main()
{
int i; // note how i is declared but not initialized
SomeFunction(out i);
Console.WriteLine(i);
return 0;
}

out关键字是C#中的新增内容,在Visual Basic和C++中没有对应的关键字,该关键字的引入使C#更安全,更不容易出错。如果在函数体中没有给out参数分配一个值,该方法就不能编译

(6) 方法的重载

C#支持方法的重载--方法的几个有不同签名(方法名相同、但参数的个数和类型不同)的版本

2. 属性

属性的概念是:它是一个方法或一对方法,在客户机代码看来,它们是一个字段

public string Name
{
get
{
return _name;
}
set
{
_name = value;
}

}

(1) 只读和只写属性

在属性定义中省略set访问器,就可以创建只读属性。

同样,在属性定义中省略get访问器,就可以创建只写属性。但是,这是不好的编程方式,因为这可能会使客户机代码的作者感到迷惑。一般情况下,如果要这么做,最好使用一个方法替代

(2) 属性的访问修饰符

C#允许给属性的get和set 访问器设置不同的访问修饰符,所以属性可以有公共的get访问器和私有或受保护的set访问器。这有助于控制属性的设置方式或时间。

(3) 自动实现的属性

如果属性的set和get访问器中没有任何逻辑,就可以使用自动实现的属性。这种属性会自动实现基础成员变量。
public string ForeName {get; set;}

不需要声明private string foreName。编译器会自动创建它

使用自动实现的属性,就不能在属性设置中进行属性的有效性验证。所以在上面的例子中,不能检查foreName是否少于20个字符。但必须有两个访问器。尝试把该属性设置为只读属性,就会出错:

每个访问器的访问级别可以不同。因此,下面的代码是合法的

public string ForeName {get; private set;}

 

3. 构造函数

在C#中声明基本构造函数的语法与在Java 和C++中相同。下面声明一个与包含的类同名的方法,但该方法没有返回类型:

public class MyClass
{
public MyClass()
{
}

没有必要给类提供构造函数,在我们的例子中没有提供这样的构造函数。一般情况下,如果没有提供任何构造函数,编译器会在后台创建一个默认的构造函数。这是一个非常基本的构造函数,它只能把所有的成员字段初始化为标准的默认值(例如,引用类型为空引用,数字数据类型为0,bool为false)。这通常就足够了,否则就需要编写自己的构造函数。

构造函数的重载遵循与其他方法相同的规则。换言之,可以为构造函数提供任意多的重载,只要它们的签名有明显的区别即可;

如果提供了带参数的构造函数,编译器就不会自动提供默认的构造函数,只有在没有定义任何构造函数时,编译器才会自动提供默认的构造函数。在下面的例子中,因为定义了一个带单个参数的构造函数,所以编译器会假定这是可以使用的唯一构造函数,不会隐式地提供其他构造函数

可以把构造函数定义为private或protected,这样不相关的类就不能访问它们

public class MyNumber
{
private int number;
private MyNumber(int number)   // another overload
{
this.number = number;
}
}

在这个例子中,我们并没有为MyNumber定义任何公共或受保护的构造函数。这就使MyNumber不能使用new运算符在外部代码中实例化(但可以在MyNumber上编写一个公共静态属性或方法,以进行实例化)。这在下面两种情况下是有用的:

● 类仅用作某些静态成员或属性的容器,因此永远不会实例化

● 希望类仅通过调用某个静态成员函数来实例化(这就是所谓对象实例化的类代理方法)

 

(1) 静态构造函数

C#的一个新特征是也可以给类编写无参数的静态构造函数。这种构造函数只执行一次,而前面的构造函数是实例构造函数,只要创建类的对象,它都会执行。

class MyClass
{
static MyClass()
{
}

}

编写静态构造函数的一个原因是,类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些静态字段和属性。

注意,静态构造函数没有访问修饰符,其他C#代码从来不调用它,但在加载类时,总是由.NET运行库调用它,所以像public和private这样的访问修饰符就没有意义了。同样,静态构造函数不能带任何参数,一个类也只能有一个静态构造函数。很显然,静态构造函数只能访问类的静态成员,不能访问实例成员。

namespace Wrox.ProCSharp.StaticConstructorSample
{
public class UserPreferences
{
public static readonly Color BackColor;

      static UserPreferences()
{
DateTime now = DateTime.Now;
if (now.DayOfWeek == DayOfWeek.Saturday
|| now.DayOfWeek == DayOfWeek.Sunday)
BackColor = Color.Green;
else
BackColor = Color.Red;
}

      private UserPreferences()
{
}
}
}这段代码说明了颜色设置如何存储在静态变量中,该静态变量在静态构造函数中进行初始化。把这个字段声明为只读类型,表示其值只能在构造函数中设置

(2) 从其他构造函数中调用构造函数

有时,在一个类中有几个构造函数,以容纳某些可选参数,这些构造函数都包含一些共同的代码

class Car
{
private string description;
private uint nWheels;

   public Car(string description, uint nWheels)
{
this.description = description;
this.nWheels = nWheels;
}

   public Car(string description) : this(model, 4)
{
}this关键字仅调用参数最匹配的那个构造函数。注意,构造函数初始化器在构造函数之前执行。现在假定运行下面的代码:

Car myCar = new Car("Proton Persona");

在本例中,在带一个参数的构造函数执行之前,先执行带2个参数的构造函数(但在本例中,因为带一个参数的构造函数没有代码,所以没有区别)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值