C#学习之C#面向对象编程(方法、事件)

方法

​ 类的属性描述了类的结构、特点和状态,类的方法描述了类的行为。类的方法也是为了解决问题域而提出的问题而设计的,为了使类能够向外部的调用代码提供某些功能,或者为了满足类内部处理数据的需要,很多时候我们都需要为一个类定义自己的方法

1. 方法的阐述

​ 方法能够携带参数执行,有的方法可以不携带参数执行,有的带多个参数才能执行,这完全取决于方法与外部调用程序的数据交换需要,方法的多个参数使用“,”分隔符隔开,并且还可以带有前缀,参数的前缀有三种,如下:

  • 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") + "元运费。";
        }
    }
}
2. 构造函数

​ 构造函数是一个类来创建实例的函数,它是一种比较特殊的函数,他的特殊性表现在如下几个方面:

  • 构造函数没有返回值,并以类名称作为函数名称
  • 声明非静态类的同时,类就具有默认的无参数构造方法,不需要编写代码
  • 子类不能使用new关键字重写父类的构造方法
  • 当函数中仅声明了带参数的构造函数,因为父类中的默认无参数构造方法已经无效,所以子类中也要声明带相同参数的构造函数,并使用base关键字继承父类构造函数
  • 访问类的静态成员之前,先执行类的静态构造方法
using System;

namespace ConstructorDemo
{
    public class Person
    {
        public string Name
        {
            get;
            set;
        }
        public int Age
        {
            get;
            set;
        }
        public Person(string name)
        {
            Name = name;
        }
        /// <summary>
        /// 使用this关键字,调用之前的Person(string name)的构造方法
        /// </summary>
        /// <param name="name"></param>
        /// <param name="age"></param>
        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 = "";
        }
    }
}
3. 析构函数

​ 相对于构造函数,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, "");
				}
		}
}
4. 静态方法

​ .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引入了拓展方法的概念。

5. 重载方法

​ 在使用C#编程语言时,会发现有时某些方法会有多重形式,比如常见的ToString()方法,在类中声明了一个方法的多种形式,称为方法的重载,方法的重载使得程序具有多种实现的方式,也增加了程序的可重用性。

​ 在C#编程语言中,只要在一个类中使用相同的方法名称,不同的参数列表,就能够实现重载,重载方法的返回类型可以相同,也可以不同,但是参数类别必须不同。

public class Book
{
		public void SendBook(string Adress)
		{
				
		}
		public void SendBook(string Adress, string Mobile)
		{
				
		}
}

​ 这里提供了两种发送书籍的方式,第一种,仅使用地址,第二种,使用地址和电话。如果只需要电话,那么无法实现,这个时候,应该定义一个enum枚举,并且将枚举作为参数的数据类型,在同一个方法中使用switch分支控制来进行判断,而不应该仅仅从重载方法的角度考虑。

6. 访问父类方法

​ 子类的子类无法从继承的类中获取继承类父类的方法,因此,之类的子类,只能够继承关系中的类型转换关系,来调用说继承类的父类中原有的方法。

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();
		}
}
7. 重载运算符

​ 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#程序时灵活地使用重载运算符,并利用运算符的优先级关系规则处理对象之间的运算,可以使代码更加简单、灵活,而且更容易阅读和理解,对于提高编程效率而言,是一个非常有效的手段。

事件
1. 事件的声明

​ 在C#编程语言中,使用event关键字来声明一个事件,声明事件的具体步骤如下:

  • 声明事件的e参数类
  • 声明事件委托
  • 声明事件

​ 熟悉面向对象的开发人员,将每一种数据状态的改变,视为一个事件,然后分别对产生的事件进行处理,把复杂的连锁反应分解成单个事件处理,使得整个系统的程序代码清晰易懂,并且具有非常好的拓展性和重用性。

​ 事件的参数继承于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;
  	/*
  			事件的数据类型是一个委托,该委托指向外部定义的事件处理方法
  	*/
}
2. 事件定义

​ 声明事件以后,接下来要做的事情就是确定事件激活的时机,在C#程序中,事件既可以被用户操作激活,也可以由数据状态的改变而激活,或者由某个判断条件来激活,激活的时机可以非常灵活,但是一定要恰当。

public void verify()
{
		DetailVerifyEvent eventarg = new DetailVerifyEvent();
		eventarg.OrderID = OrderID;
		eventarg.GoodsID = GoodsID;
		// 激发事件
		OnVerify(tis, eventarg);
}

​ 事件的定义需要4个步骤:声明事件的参数类型、声明事件的委托、声明事件、在特定的方法执行的激活事件。

3. 事件处理方法

​ 事件处理方法是为了响应事件而编写的,事件的定义重视期待外部程序的响应,外部程序对事件的响应由事件处理方法来完成。在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();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wells Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值