扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
索引器提供了一种以与数组相同的方式访问类或结构的方法。例如,我们可能有表示我们公司内某个部门的类。这个类可以包含该部门中所有雇员的名字,而索引器可以允许我们访问这些名字,如下所示:
myDepartment[0] = "Fred"; myDepartment[1] = "Barney";
等等。在类的定义中,通过定义具有如下签名的属性,可以启用索引器:
public type this [int index]
然后,我们提供 get 和 set 方法作为标准属性,而当使用索引器时,这些访问器指定哪些内部成员被引用。
在下面的简单示例中,我们创建了一个名为 Department 的类,此类使用索引器来访问该部门的雇员(在内部表示为一个字符串数组):
using System; public class Department { private string name; private const int MAX_EMPLOYEES = 10; private string [] employees = new string [MAX_EMPLOYEES]; public Department(string deptName) { name = deptName; } public string this [int index] { get { if (index >= 0 && index < MAX_EMPLOYEES) { return employees[index]; } else { throw new IndexOutOfRangeException(); //return "Error"; } } set { if (index >= 0 && index < MAX_EMPLOYEES) { employees[index] = value; } else { throw new IndexOutOfRangeException(); //return "Error"; } } } // Other methods and properties as usual }
然后,我们可以创建这个类的一个实例,并且对其进行访问,如下所示:
using System; public class SalesDept { public static void Main(string[] args) { Department sales = new Department("Sales"); sales[0] = "Nikki"; sales[1] = "Becky"; Console.WriteLine("The sales team is {0} and {1}", sales[0], sales[1]); } }
有关索引器的更多信息,请参见 Indexer。
为了增加有关类型的声明性信息,C# 引入一种叫做属性的新机制。有关类型的其他信息放在类型定义前面的声明性标记中。下面的示例向您展示了如何利用 .NET 框架属性来修饰一个类或方法。
在下面的示例中,通过添加 WebMethod 属性,GetTime 方法被标记为一个 XML Web 服务。
using System; using System.Web.Services; public class Utilities : WebService { [WebMethod] public string GetTime() { return DateTime.Now.ToShortTimeString(); } }
通过添加 CODE>WebMethod 属性,.NET 框架现在会自动处理调用此函数所必需的 XML/SOAP 交换。可以调用这个 Web 服务来检索下列值:
<?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/">7:26 PM</string>
在下面的示例中,通过添加 Serializable() 属性,Employee 类被标记为 Serializable。虽然 salary 字段被标记为 public,但是它不会被序列化,因为它是用 NonSerialized() 属性标记的。
using System; [Serializable()] public class Employee { public int ID; public string Name; [NonSerialized()] public int Salary; }
有关创建自定义属性的信息,请参见 Creating Custom Attributes。
C++、Pascal 和其他一些支持函数指针概念的语言都允许我们在运行时选择我们希望调用的函数。
Java 并没有提供任何具有函数指针功能的结构,但是 C# 却通过 System.Delegate 类提供了此功能。一个委托实例封装一个方法,它是一个可调用实体。
对于实例方法,委托由包含类的实例以及该实例中的方法组成。对于静态方法,可调用实体由一个类和此类中的静态方法组成。因此,委托可用于调用任意对象的函数,并且委托是面向对象、类型安全且可靠的。
在定义和使用委托时有三个步骤:
声明
实例化
调用
我们可以用下面的语法声明一个委托:
delegate void myDelegate();
然后,就可以用这个委托来引用返回 void 而且不带任何参数的所有函数。
类似地,要为带有 string 参数并返回 long 的任何函数创建一个委托,我们应该使用下面的语法:
delegate long myDelegate(string mystring);
然后,我们就可以将该委托指派给具有此签名的任何方法,如下所示:
myDelegate operation = new myDelegate(methodName);
委托对象是不可改变的,也就是说,与它们匹配的签名一旦设置就不能改变。然而,我们可以指向另一个方法,只要它们都具有相同的签名即可。例如:
delegate myDelegate(int a, int b) myDelegate operation = new myDelegate(Add); operation = new myDelegate(Multiply);
这里,我们将 operation 重新指派给一个新的委托对象,这样 operation 就可以调用 Multiply 方法。只有 Add() 和 Multiply() 都具有相同的签名时,我们才可以这样做。
调用委托相当简单,只需要将委托变量的名称替换成方法的名称即可:
delegate long myDelegate(int i, int j); myDelegate operation = new myDelegate(Add); long lresult = operation(10, 20);
这里用值 10 和 20 调用 Add 方法,返回一个长整型结果,并将其赋给变量 lresult。
让我们创建一个程序来快速地演示委托的创建、实例化和调用:
using System; public class DelegateClass { delegate long myDelegate (int i, int j); public static void Main(string[] args) { myDelegate operation = new myDelegate(MathClass.Add); Console.WriteLine("Call to Add method through delegate"); long l = operation(10, 20); Console.WriteLine("Sum of 10 and 20 is " + l); Console.WriteLine("Call to Multiply method thru delegate"); operation = new myDelegate(MathClass.Multiply); l = operation(1639, 1525); Console.WriteLine("1639 multiplied by 1525 equals " + l); } } public class MathClass { public static long Add (int i, int j) { return (i+j); } public static long Multiply (int i, int j) { return (i*j); } }
我们会得到这样的输出:
Call to Add method through delegate Sum of 10 and 20 is 30 Call to Multiply method through delegate 1639 multiplied by 1525 equals 2499475
如前所述,委托实例必须包含对象引用。在上面的示例中,通过将方法声明为静态的(意味着我们自己不需要指定对象引用),我们避免了这样做。然而,如果委托引用一个实例方法,就必须给出对象引用,如下所示:
MathClass obj = new MathClass(); myDelegate operation = new myDelegate(obj.Power);
其中,Power 是 MathClass 方法的一个实例。因此,如果 MathClass 的方法没有声明为静态的,我们就可以通过委托来调用它们,如下所示:
using System; public class DelegateClass { delegate long myDelegate(int i, int j); public static void Main(string[] args) { MathClass mathObj = new MathClass(); myDelegate operation = new myDelegate(mathObj.Add); Console.WriteLine("Call to Add method through delegate"); long l = operation(10, 20); Console.WriteLine("Sum of 10 and 20 is " + l); Console.WriteLine("Call to Multiply method thru delegate"); operation = new myDelegate(mathObj.Multiply); l = operation(1639, 1525); Console.WriteLine("1639 multiplied by 1525 equals " + l); } }
当这些方法声明为 static 时,如果您运行此程序,您就会得到同前面一样的输出。
.NET 框架也将委托广泛应用于事件处理任务(像 Windows 或 Web 应用程序中的按钮单击事件)。虽然在 Java 中事件处理通常通过实现自定义侦听器类来完成,但是 C# 开发人员可以利用委托来进行事件处理。事件被声明为带有委托类型的字段,只是在事件声明前面加上 event 关键字。通常,事件被声明为公共的,但是任何可访问性修饰符都是允许的。下面的代码显示了委托和事件的声明。
public delegate void CustomEventHandler(object sender, EventArgs e); public event CustomEventHandler CustomEvent;
事件委托是多路广播的,这意味着它们可以具有对多个事件处理方法的引用。通过维护事件的注册事件处理程序列表,委托可以担当引发事件的类的事件发送程序。下面的示例向您展示了可以如何给多个函数预订事件。类 EventClass 包含委托、事件和调用事件的方法。注意,只能从声明事件的类中调用事件。然后,类 TestClass 就可以使用 +=/-= 运算符来预订/取消预订事件。当调用 InvokeEvent() 方法时,它会激发此事件,而已经预订此事件的任何函数都会同步激发,如下面的代码所示:
using System; class TestClass { static void Main(string[] args) { EventClass myEventClass = new EventClass(); // Associate the handler with the events myEventClass.CustomEvent += new EventClass.CustomEventHandler(CustomEvent1); myEventClass.CustomEvent += new EventClass.CustomEventHandler(CustomEvent2); myEventClass.InvokeEvent(); myEventClass.CustomEvent -= new EventClass.CustomEventHandler(CustomEvent2); myEventClass.InvokeEvent(); } private static void CustomEvent1(object sender, EventArgs e) { Console.WriteLine("Fire Event 1"); } private static void CustomEvent2(object sender, EventArgs e) { Console.WriteLine("Fire Event 2"); } } public class EventClass { public delegate void CustomEventHandler(object sender, EventArgs e); //Declare the event using the delegate datatype public event CustomEventHandler CustomEvent; public void InvokeEvent() { CustomEvent(this, EventArgs.Empty); } }
此程序的输出如下:
Fire Event 1 Fire Event 2 Fire Event 1查看本文来源
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者