标签:委托 delegate 多播委托 actiont与funct 委托泛化
委托
我们习惯性的把数据当做参数传递给方法,如果给方法传递一个方法呢?但是往往有时候我们要给一个方法传递另一个方法。更麻烦的是,有时候我们并不知道程序在编译时才知道应该传递哪一个方法。但是.NET Framework语法是不允许直接调用方法的,必须把方法的细节封装在一种新类型的对象中,这个新类型就是委托。关键字是delegate。委托是一个特殊的类型对象,其特殊之处在于,我们以前定义的对象包含的是数据,但是委托保护哈韩的只是一个方法或多个方法的地址。
Delegate类:
Delegate 类是委托类型的基类。 然而,只有系统和编译器可以显式地从Delegate 类或 MulticastDelegate 类派生。此外,还不允许从委托类型派生新类型。 Delegate 类不是委托类型,该类用于派生委托类型。
大多数语言实现 delegate 关键字,这些语言的编译器能够从 MulticastDelegate 类进行派生;所以,用户应当使用语言所提供的 delegate 关键字。
公共语言运行时为每个委托类型提供 Invoke 方法(使用与该委托相同的签名)。不必从 C#、Visual Basic 或 Visual C++ 显式调用此方法,因为编译器将自动调用此方法。需要查找委托类型的签名时 Invoke 方法在反射 上很有用。
托管语言使用 Combine 和 Remove 方法实现委托操作。示例包括 Visual Basic 中的 AddHandler 和 RemoveHandler 语句以及 C# 中委托类型上的 += 和 -= 运算符。
下面这个例子有三种委托的使用方法;
首先要定义一个委托:没有public delegate string GetString();
第一种直接把系统方法绑定到委托上:
GetString g = new GetString(i.ToString);
g();
第二种:把系统方法ToString()委托给GetString
GetString g = i.ToString;
g();
第三种:通过结构体进行委托。
g = new GetString(c.GetCurrency);
g();
class Program
{
//定义一个没有参数,返回值为string 类型的委托。
//define delegate no parameter and return string
public delegate string GetString();
static void Main(string[] args)
{
int i = 40;
//直接把系统方法ToString()委托给GetString
// GetString g = new GetString(i.ToString);
//使用另一种方法把系统方法ToString()委托给GetString
GetString g = i.ToString;
Console.WriteLine( "string is "+ g() );
//通过结构体使用委托
Currency c = new Currency(34, 50);
g = c.ToString;
Console.WriteLine("string is " + g());
g = new GetString(c.GetCurrency);
Console.WriteLine("string is " + g());
Console.ReadKey();
}
}
struct Currency
{
public uint Dollars;
public ushort Cents;
public Currency(uint Dollars,ushort Cents)
{
this.Dollars = Dollars;
this.Cents = Cents;
}
public override string ToString()
{
return string.Format("${0}.{ 1,2:00}",this.Dollars,this.Cents);
}
public string GetCurrency()
{
return "Dollar";
}
public static explicit operator Currency(float value)
{
//checked是什么意思。
checked
{
uint dollars=(uint )value ;
ushort cents = (ushort)((value - dollars) * 100);
return new Currency(dollars,cents);
}
}
//对float类型进行重载。
public static implicit operator float (Currency value)
{
return value.Dollars+(value.Cents/100.0f);
}
//对Currency类型进行重载
public static implicit operator Currency (uint value)
{
return new Currency(value, 0);
}
//对uint类型进行重载。。
public static implicit operator uint(Currency value)
{
return value.Dollars;
}
}
如果你是一个合格的程序员,请认真思考程序中一下三个问题:
1、 checked关键字是干嘛用的?
2、 还有结构体最后三个函数是什么意思?(点击获得答案。)
3、 string.Format("${0}.{ 1,2:00}",this.Dollars,this.Cents);其中${0}.{1,2:00}如何实现的?
下面这个例子,仅仅使用委托来调用两个不同的操作。它说明了如何把委托传递给方法,如何使用委托数组。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestDelegateSimple
{
delegate double DoubleOp(double value);
class Program
{
static void Main(string[] args)
{
DoubleOp[] options = { MathOptions.MultiplyTwo, MathOptions.Square};
for (int i = 0; i < options.Length; i++)
{
Console.WriteLine("using option[{0}]",i);
ProcessAndDisplayNumber(options[i], 2.0);
ProcessAndDisplayNumber(options[i], 7.94);
ProcessAndDisplayNumber(options[i], 1.414);
}
Console.ReadKey();
}
private static void ProcessAndDisplayNumber(DoubleOp d,double value)
{
double d1 = d(value);
Console.WriteLine("value is {0},result of option is {1}",value,d1);
}
}
class MathOptions
{
public static double MultiplyTwo(double value)
{
return value * 2;
}
public static double Square(double value)
{
return value * value;
}
}
}
前面使用的都是包含一个方法的调用,如果想调用多个方法,就需要多次显示调用这个委托,也可以包含多个方法,这种成为委托多播。
把上一个例子改为多播的情况:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DuoBoDelegate
{
class Program
{
static void Main(string[] args)
{
Action <double >options = MathOptions.MultiplyTwo;
options+=MathOptions.Square;
ProcessAndDisplayNumber(options, 2.0);
ProcessAndDisplayNumber(options, 7.94);
ProcessAndDisplayNumber(options, 1.414);
Console.ReadKey();
}
private static void ProcessAndDisplayNumber(Action<double> d, double value)
{
Console.WriteLine();
Console.WriteLine("value is {0},result of option is", value);
d(value);
}
}
class MathOptions
{
public static void MultiplyTwo(double value)
{
double result = value * 2;
Console.WriteLine("MutiplyTwo by 2:{0} give {1}",value,result);
}
public static void Square(double value)
{
double result = value * value;
Console.WriteLine("MutiplyTwo by 2:{0} give {1}", value, result);
}
}
}
委托泛型:Action<T>与Func<T>委托。
除了上面的定义委托的方法还可以使用这两种方法定义委托。
Action<T>:表示引用一个void返回类型的方法。Action<inT1>表示一个参数的没有返回的委托。Action<in T1,in T2>表示两个参数的没有返回的委托。
Func<T>:表示引用一个有返回类型的方法。Func<inT1,out TResult>,表示一个参数的有返回值的参数。
上一个例子只是说明了委托的多种实现,并没有很好的说明,没有委托不能实现这些方法。他有一个类BubbleSorter,该类实现了一个排序算法,没有委托很难编写这个类。这个类可以排序任何一种类型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BobbleSorter
{
class Program
{
static void Main(string[] args)
{
Employee[] employee = {
new Employee("jack",1220),
new Employee("jason",2),
new Employee("jonee",2999),
new Employee("alvin",100),
};
BubbleSorter.Sort(employee, Employee.CompareSalary);
foreach (var item in employee)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
//排序类
#region Sorter Class
class BubbleSorter
{
public BubbleSorter()
{
}
public static void Sort<T>(IList<T> sortArray,Func<T,T,bool> comparsion)
{
bool swapped = true;
do
{
swapped = false;
for (int i = 0; i < sortArray.Count-1; i++)
{
if (comparsion(sortArray[i+1],sortArray[i]))
{
T temp = sortArray[i];
sortArray[i] = sortArray[i + 1];
sortArray[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
}
}
#endregion
//员工类
#region Employee Class
class Employee
{
private string name;
private decimal salary;
public decimal Salary
{
get { return salary; }
set { salary = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
public Employee()
{
}
public Employee(string name,decimal salary)
{
this.name = name;
this.salary = salary;
}
public override string ToString()
{
return string.Format("{0},{1:C}",this.name,this.salary);
}
public static bool CompareSalary(Employee e1, Employee e2)
{
return e1.Salary < e2.Salary;
}
}
#endregion
}
思考:为什么类中方法public static void Sort<T>(IList<T>sortArray,Func<T,T,bool> comparsion)
参数为什么是Ilist泛型集合,但是传入的一个数组?
匿名方法就是使一段代码作为委托的参数。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NiMingDelegate
{
class Program
{
static void Main(string[] args)
{
string mid = ",middle part,";
Func<string, string> anonDel = delegate(string para)
{
para += mid;
para += "and this is add the string";
return para;
};
Console.WriteLine(anonDel("Start of string"));
Console.ReadKey();
}
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:委托 delegate 多播委托 actiont与funct 委托泛化
原文地址:http://blog.csdn.net/alvin930403/article/details/46924531