类的属性描述了类的结构、特点和状态,类的方法描述了类的行为。类的方法也是为了解决问题域而提出的问题而设计的,为了使类能够向外部的调用代码提供某些功能,或者为了满足类内部处理数据的需要,很多时候我们都需要为一个类定义自己的方法
方法能够携带参数执行,有的方法可以不携带参数执行,有的带多个参数才能执行,这完全取决于方法与外部调用程序的数据交换需要,方法的多个参数使用“,”分隔符隔开,并且还可以带有前缀,参数的前缀有三种,如下:
ref前缀不错参数按引用传递,方法内部的代码对该参数进行的任何修改,都返回到ref前缀的参数,ref参数要求在调用方法前完成初始化
out前缀也表示参数按引用传递,方法内部的修改同样会反映到out前缀的参数中,当不要求方法前完成初始化,是必须在方法内部完成参数的初始化
param前缀表示参数数量是可变的。使用param作为参数前缀的方法,一般需要在方法内部编写检查参数的代码
这里需要注意,不能将类中定义的属性或索引器作为ref参数或者out参数传递,这是因为,尽管在类外部可以好像变量一样调用,当属性的本质还是方法,如果没有定义存储属性的变量,ref或者out参数在使用的时候就无法获得分配的内存地址。
using System;
namespace ParameterDemo
{
public class FreightageInfo
{
public string FreightageMessage
{
get;
set;
}
public decimal Freightage
{
get;
set;
}
}
public class Book
{
private FreightageInfo _PurchaseInfo;
public string BookName
{
get;
set;
}
public decimal Price
{
get;
set;
}
/*
因为使用ref前缀修饰Freightage类型的参数,所以需要在方法调用之前创建类实例
*/
public FreightageInfo PurchaseInfo
{
get
{
_PurchaseInfo = new FreightageInfo();
ComputeFreightage(ref _PurchaseInfo);
return _PurchaseInfo;
}
}
/*
如果使用out前缀修饰Freightage类型的参数,则应该在方法内部创建类实例
*/
private void ComputeFreightage(ref FreightageInfo PurchaseData)
{
PurchaseData.Freightage = Price * 0.1m;
PurchaseData.FreightageMessage =
"您需要支付" + PurchaseData.Freightage.ToString("G0") + "元运费。";
}
}
}
构造函数是一个类来创建实例的函数,它是一种比较特殊的函数,他的特殊性表现在如下几个方面:
using System;
namespace ConstructorDemo
{
public class Person
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
public Person(string name)
{
Name = name;
}
///
/// 使用this关键字,调用之前的Person(string name)的构造方法
///
///
///
public Person(string name, int age)
: this(name)
{
Age = age;
}
}
public class Customer : Person
{
public string Mobile
{
get;
set;
}
public string Adrress
{
get;
set;
}
/*
因为父类的默认无参构造函数已经无效,所以这个构造函数必须显示地继承父类的构造函数,
使用base关键字继承Person类的构造函数
*/
public Customer(string name) : base(name)
{
Mobile = "";
Adrress = "";
}
}
}
相对于构造函数,C#编程语言中的析构函数用来析构类的实例。因为.NET Framework的垃圾回收器机制决定了类实例占用的内存是否可以回收,并决定何时释放,所以在程序中无法确定析构函数何时执行,另外,和构造函数不同的是,析构函数不能构定义,也不能直接调用。
在类中定义析构函数,不能使用任何修饰符,而必须以“~类名称”的形式来声明,并且不能带有参数。执行析构函数的时候,实际上已经执行了object基类的Finalize方法来释放内存,所以我们在析构函数中说要编写的代码,只是为了在释放内存时顺带处理一些事情。
public static class GlobalInfo
{
public static string UserList
{
get;
set;
}
public class User
{
public string UserName
{
get;
set;
}
/*
析构函数并没有对User类实例进行内存上的操作,实际上这一步操作时由.NET Framework完成的,开发人员不用干涉
析构函数中常常写顺便处理的代码而已
*/
~User()
{
// 删除在线列表的用户
GlobalInfo.UserList = GlobalInfo.UserList.Replace(UserName, "");
}
}
}
.NET Framework在内存中分配了一块特别的区域,称为静态区域,尽管在程序运行的过程中随时手可能改变这个区域中变量的内容,当却不能改变它所用的内存空间大小。这里的“静态”,是指内存占用空间不改变,这一点和“const”关键字定义的常量是有区别的。
在C#编程语言中可以在一个类中定义静态方法,静态方法不必创建类的实例就能够调用,这在一些场合是非常方便的,静态方法有以下四个特点:
public class StaticLibrary
{
public static int Factorial(int Input)
{
int result = 1;
for ( ; Input > 0; Input-- )
{
result *= Input;
}
return result;
}
/*
该方法调用的方式:StaticLibrary.Factorial(5);
*/
}
静态方法的用途很广,我们可以把一些比较通用的代码都组织成为静态方法,在C#2008引入了拓展方法的概念。
在使用C#编程语言时,会发现有时某些方法会有多重形式,比如常见的ToString()方法,在类中声明了一个方法的多种形式,称为方法的重载,方法的重载使得程序具有多种实现的方式,也增加了程序的可重用性。
在C#编程语言中,只要在一个类中使用相同的方法名称,不同的参数列表,就能够实现重载,重载方法的返回类型可以相同,也可以不同,但是参数类别必须不同。
public class Book
{
public void SendBook(string Adress)
{
}
public void SendBook(string Adress, string Mobile)
{
}
}
这里提供了两种发送书籍的方式,第一种,仅使用地址,第二种,使用地址和电话。如果只需要电话,那么无法实现,这个时候,应该定义一个enum枚举,并且将枚举作为参数的数据类型,在同一个方法中使用switch分支控制来进行判断,而不应该仅仅从重载方法的角度考虑。
子类的子类无法从继承的类中获取继承类父类的方法,因此,之类的子类,只能够继承关系中的类型转换关系,来调用说继承类的父类中原有的方法。
public class Order
{
public virtual void WriteLog()
{
}
}
public class SaleOrder : Order
{
public new void WriteLog()
{
}
}
public class VIPSaleOrder : SaleOrder
{
public void WriteLog()
{
/*
将当前类实例转换为Order实例
*/
Order viporder = this as SaleOrder;
viporder.WriteLog();
}
}
C#编程语言的运算符可以重载。
class Order
{
public decimal Quantity
{
get;
set;
}
public decimal Price
{
get;
set;
}
public string Carge
{
get;
set;
}
public static decimal operator + (Order Order1, Order order2)
{
decimal Order1Charge = Order1.Price * Order1.Quantity;
decimal Order2Charge = Order2.Price * Order2.Quantity;
return Order1Charge + Order2Charge;
}
}
C#中可以重载的运算符包括:
在编写C#程序时灵活地使用重载运算符,并利用运算符的优先级关系规则处理对象之间的运算,可以使代码更加简单、灵活,而且更容易阅读和理解,对于提高编程效率而言,是一个非常有效的手段。
在C#编程语言中,使用event关键字来声明一个事件,声明事件的具体步骤如下:
熟悉面向对象的开发人员,将每一种数据状态的改变,视为一个事件,然后分别对产生的事件进行处理,把复杂的连锁反应分解成单个事件处理,使得整个系统的程序代码清晰易懂,并且具有非常好的拓展性和重用性。
事件的参数继承于EventArgs类,表示处理事件时需要获取的参数对象,在参数对象中需要包含足够多的信息,以便在事件处理时,能够获取所需要的数据。
接下来要声明的事事件委托,产生的事件是要处理的,然而一个类只能产生事件,而不能提供处理方法,这时候我们只能把处理事件的方法放在类的外部,我们只知道事情发生的时候找谁就好了,这为程序带来了灵活性。
我们在程序中定义委托,来指向事件处理方法。
定义事件所携带的参数类,以及事件处理方法的委托后,就可以声明一个事件了。如果事件不需要传递数据,可以不声明参数类,直接使用EventArgs的类实例也是可以的。
// 事件参数
public class DetailVerifyEvent : EventArgs
{
public int OrderID
{
get;
set;
}
public int GoodsID
{
get;
set;
}
}
class OrderDetail
{
public int OrderID
{
get;
set;
}
public int GoodsID
{
get;
set;
}
public decimal Quantity
{
get;
set;
}
// 审核事件的委托
public delegate void VerifyHandler(object Sender, DetailVerifyEvent e);
// 声明事件
public event VerifyHandler OnVerify;
/*
事件的数据类型是一个委托,该委托指向外部定义的事件处理方法
*/
}
声明事件以后,接下来要做的事情就是确定事件激活的时机,在C#程序中,事件既可以被用户操作激活,也可以由数据状态的改变而激活,或者由某个判断条件来激活,激活的时机可以非常灵活,但是一定要恰当。
public void verify()
{
DetailVerifyEvent eventarg = new DetailVerifyEvent();
eventarg.OrderID = OrderID;
eventarg.GoodsID = GoodsID;
// 激发事件
OnVerify(tis, eventarg);
}
事件的定义需要4个步骤:声明事件的参数类型、声明事件的委托、声明事件、在特定的方法执行的激活事件。
事件处理方法是为了响应事件而编写的,事件的定义重视期待外部程序的响应,外部程序对事件的响应由事件处理方法来完成。在C#编程语言中,事件处理方法由委托指定,事件产生的时候并不确定该调用什么方法,甚至不确定是否存在可调用的方法,事件只能通过委托来寻找外部响应事件的处理方法。
C#之所以采用这种事件响应机制,是为了满足系统设计“强内聚,低耦合”的要求。使用委托指定的事件处理方法的机制,既保证类或模块的独立性,也保证了类和类之间已非常松散的机制来互相调用。通过事件以及其响应事件,编写出符合系统设计要求的程序。
using System;
namespace Test
{
public class DetailVerifyEvent : EventArgs
{
public int OrderID
{
get;
set;
}
public int GoodsID
{
get;
set;
}
}
class OrderDetail
{
public int OrderID
{
get;
set;
}
public int GoodsID
{
get;
set;
}
public decimal Quantity
{
get;
set;
}
public delegate void VerifyHandler(object Sender, DetailVerifyEvent e);
public event VerifyHandler OnVerify;
public void Verify()
{
DetailVerifyEvent eventarg = new DetailVerifyEvent();
eventarg.OrderID = OrderID;
eventarg.GoodsID = GoodsID;
OnVerify(this, eventarg);
}
}
public partial class _Default : System.Web.UI.Page
{
private OrderDetail DetailInstance;
protected void Page_Load(object sender, EventArgs e)
{
DetailInstance = new OrderDetail();
DetailInstance.OrderID = 1;
DetailInstance.Quantity = 20;
DetailInstance.GoodsID = 12;
DetailInstance.OnVerify += new OrderDetail.VerifyHandler(DetailInstance_OnVerify);
}
}
void DetailInstance_OnVerify(object Sender, DetailVerifyEvent e)
{
Response.Write(e.OrderID);
}
protected void Button1_Click(object sender, EventArgs e)
{
DetailInstance.Verify();
}
}