委托对于学习C#语言得初学者,一定是一个阻碍,最起码对我来说,最开始只知道怎么用,直到工作了两三年,才彻底搞懂里面得含义。也可能是我个人比较笨吧。
1.1 C语言指针
了解委托之前先了解下c的指针函数。如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
函数指针的使用:
#include <stdio.h>
#include<iostream>
int Count(int a, int b);
int main() {
int (*p)(int, int);
p = Count;
int c = p(10, 20);
std::cout << c;
}
int Count(int a,int b) {
return a + b;
}
1.2 初识委托
委托是一种存储函数引用的类型,在事件和事件的处理时有重要的用途通俗的说,委托是一个可以引用方法的类型,当创建一个委托,也就创建一个引用方法的变量,进而就可以调用那个方法,即委托可以调用它所指的方法。委托也可以简单理解为指向方法得指针。
1.2.1 委托代码示例(来源CLR VIA C#)
下面这串代码并不难,新手也能看懂。照着写一遍。
class Program
{
private delegate void FeedBack(Int32 item);
static void Main(string[] args)
{
ChainDelegateDemo2();
}
//委托调用静态方法
private static void DelegateStaticDemo()
{
ShowCount(1, 20, null);
ShowCount(1, 20, new FeedBack(FeedbackConsole));
ShowCount(1, 20, new FeedBack(FeedbackMessageBox));
Console.ReadKey();
}
//委托调用实例方法
private static void InstanceDelegateDemo()
{
ShowCount(1, 20, new Program().FeedbackStream);
Console.ReadLine();
}
//委托调用实例方法
private static void ChainDelegateDemo()
{
FeedBack fb1 = new FeedBack(FeedbackConsole);
FeedBack fb2 = new FeedBack(FeedbackMessageBox);
FeedBack fb3 = new FeedBack(new Program(). FeedbackStream);
FeedBack fc = null;
fc = (FeedBack)Delegate.Combine(fc, fb1);
fc = (FeedBack)Delegate.Combine(fc, fb2);
fc = (FeedBack)Delegate.Combine(fc, fb3);
// ShowCount(1, 2, fc);
fc=(FeedBack) Delegate.Remove(fc, new FeedBack(FeedbackConsole));
ShowCount(1, 2, fc);
Console.ReadKey();
}
private static void ChainDelegateDemo2()
{
FeedBack fb1 = new FeedBack(FeedbackConsole);
FeedBack fb2 = new FeedBack(FeedbackMessageBox);
FeedBack fb3 = new FeedBack(new Program().FeedbackStream);
FeedBack fc = null;
fc += fb1;
fc += fb2;
fc += fb3;
fc -= fb1;
// ShowCount(1, 2, fc);
ShowCount(1, 2, fc);
Console.ReadKey();
}
private static void ShowCount(Int32 from, Int32 to, FeedBack fb)
{
for (int i = from; i <= to; i++)
{
if (fb != null)
fb(i);
}
}
private static void FeedbackConsole(Int32 item)
{
Console.WriteLine(item.ToString());
}
private static void FeedbackMessageBox(Int32 item)
{
MessageBox.Show (item.ToString());
}
private void FeedbackStream(Int32 item)
{
using(StreamWriter st=new StreamWriter("ssss", true))
{
st.Write(item.ToString());
}
}
}
当前所有得方法都写到一个类里面了,其实这些方法即使写入其他类里面,只要委托类型足够安全,便没有任何问题.
1.2.2 委托得逆变性和协变性
逆变性:方法获得得参数可以是委托得参数类型得基类。
协变性性:方法能发挥委托返回类型派生得类型
delegate object macll(FileStream st)
string Methond(Stream st)
在这里,返回值类型是委托得派生类,协变性允许,FileStream是Stream子类,逆变性允许
1.2.3 委托解密
首先看一下委托得IL代码
.class nested private auto ansi sealed FeedBack
extends [mscorlib]System.MulticastDelegate
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method FeedBack::.ctor
.method public hidebysig newslot virtual
instance void Invoke (
int32 item
) runtime managed
{
} // end of method FeedBack::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult BeginInvoke (
int32 item,
class [mscorlib]System.AsyncCallback callback,
object 'object'
) runtime managed
{
} // end of method FeedBack::BeginInvoke
.method public hidebysig newslot virtual
instance void EndInvoke (
class [mscorlib]System.IAsyncResult result
) runtime managed
{
} // end of method FeedBack::EndInvoke
} // end of class FeedBack
定义得委托自动继承了System.MulticastDelegate,所有得委托均继承此类,编译器定义了四个方法,一个构造器,一个Invoke,一个BeginInvoke,一个EndInvoke。
由于所有委托类型都继承System.MulticastDelegate,所以也继承System.MulticastDelegate的属性和方法,在所有属性和方法里面,有三个非公字段是最重要的。
tip:MulticastDelegate是一个特殊的类,编译器和其他工具可以派生,代码里不可以显示派生。
Source Browser 可以在这里看MulticastDelegate的源代码
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace System
{
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public abstract class MulticastDelegate : Delegate
{
// This is set under 2 circumstances
// 1. Multicast delegate
// 2. Wrapper delegate
private object? _invocationList; // Initialized by VM as needed
private IntPtr _invocationCount;
// This constructor is called from the class generated by the
// compiler generated code (This must match the constructor
// in Delegate
[RequiresUnreferencedCode("The target method might be removed")]
protected MulticastDelegate(object target, string method) : base(target, method)
{
}
// This constructor is called from a class to generate a
// delegate based upon a static method name and the Type object
// for the class defining the method.
protected MulticastDelegate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type target, string method) : base(target, method)
{
}
internal bool IsUnmanagedFunctionPtr()
{
return _invocationCount == (IntPtr)(-1);
}
internal bool InvocationListLogicallyNull()
{
return (_invocationList == null) || (_invocationList is LoaderAllocator) || (_invocationList is System.Reflection.Emit.DynamicResolver);
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new SerializationException(SR.Serialization_DelegatesNotSupported);
}
// equals returns true IIF the delegate is not null and has the
// same target, method and invocation list as this object
public sealed override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj == null)
return false;
if (object.ReferenceEquals(this, obj))
return true;
if (!InternalEqualTypes(this, obj))
return false;
// Since this is a MulticastDelegate and we know
// the types are the same, obj should also be a
// MulticastDelegate
Debug.Assert(obj is MulticastDelegate, "Shouldn't have failed here since we already checked the types are the same!");
MulticastDelegate d = Unsafe.As<MulticastDelegate>(obj);
if (_invocationCount != (IntPtr)0)
{
// there are 4 kind of delegate kinds that fall into this bucket
// 1- Multicast (_invocationList is Object[])
// 2- Wrapper (_invocationList is Delegate)
// 3- Unmanaged FntPtr (_invocationList == null)
// 4- Open virtual (_invocationCount == MethodDesc of target, _invocationList == null, LoaderAllocator, or DynamicResolver)
if (InvocationListLogicallyNull())
{
if (IsUnmanagedFunctionPtr())
{
if (!d.IsUnmanagedFunctionPtr())
return false;
return CompareUnmanagedFunctionPtrs(this, d);
}
// now we know 'this' is not a special one, so we can work out what the other is
if (d._invocationList is Delegate)
// this is a wrapper delegate so we need to unwrap and check the inner one
return Equals(d._invocationList);
return base.Equals(obj);
}
else
{
if (_invocationList is Delegate invocationListDelegate)
{
// this is a wrapper delegate so we need to unwrap and check the inner one
return invocationListDelegate.Equals(obj);
}
else
{
Debug.Assert(_invocationList is object[], "empty invocation list on multicast delegate");
return InvocationListEquals(d);
}
}
}
else
{
// among the several kind of delegates falling into this bucket one has got a non
// empty _invocationList (open static with special sig)
// to be equals we need to check that _invocationList matches (both null is fine)
// and call the base.Equals()
if (!InvocationListLogicallyNull())
{
if (!_invocationList!.Equals(d._invocationList))
return false;
return base.Equals(d);
}
// now we know 'this' is not a special one, so we can work out what the other is
if (d._invocationList is Delegate)
// this is a wrapper delegate so we need to unwrap and check the inner one
return Equals(d._invocationList);
// now we can call on the base
return base.Equals(d);
}
}
// Recursive function which will check for equality of the invocation list.
private bool InvocationListEquals(MulticastDelegate d)
{
Debug.Assert(d != null);
Debug.Assert(_invocationList is object[]);
object[] invocationList = (object[])_invocationList;
if (d._invocationCount != _invocationCount)
return false;
int invocationCount = (int)_invocationCount;
for (int i = 0; i < invocationCount; i++)
{
Debug.Assert(invocationList[i] is Delegate);
Delegate dd = (Delegate)invocationList[i]; // If invocationList is an object[], it always contains Delegate (or MulticastDelegate) objects
object[] dInvocationList = (d._invocationList as object[])!;
if (!dd.Equals(dInvocationList[i]))
return false;
}
return true;
}
private static bool TrySetSlot(object?[] a, int index, object o)
{
if (a[index] == null && System.Threading.Interlocked.CompareExchange<object?>(ref a[index], o, null) == null)
return true;
// The slot may be already set because we have added and removed the same method before.
// Optimize this case, because it's cheaper than copying the array.
if (a[index] is object ai)
{
MulticastDelegate d = (MulticastDelegate)o;
MulticastDelegate dd = (MulticastDelegate)ai;
if (dd._methodPtr == d._methodPtr &&
dd._target == d._target &&
dd._methodPtrAux == d._methodPtrAux)
{
return true;
}
}
return false;
}
private MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready)
{
// First, allocate a new multicast delegate just like this one, i.e. same type as the this object
MulticastDelegate result = (MulticastDelegate)InternalAllocLike(this);
// Performance optimization - if this already points to a true multicast delegate,
// copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them
if (thisIsMultiCastAlready)
{
result._methodPtr = this._methodPtr;
result._methodPtrAux = this._methodPtrAux;
}
else
{
result._methodPtr = GetMulticastInvoke();
result._methodPtrAux = GetInvokeMethod();
}
result._target = result;
result._invocationList = invocationList;
result._invocationCount = (IntPtr)invocationCount;
return result;
}
internal MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount)
{
return NewMulticastDelegate(invocationList, invocationCount, false);
}
internal void StoreDynamicMethod(MethodInfo dynamicMethod)
{
if (_invocationCount != (IntPtr)0)
{
Debug.Assert(!IsUnmanagedFunctionPtr(), "dynamic method and unmanaged fntptr delegate combined");
// must be a secure/wrapper one, unwrap and save
MulticastDelegate d = ((MulticastDelegate?)_invocationList)!;
d._methodBase = dynamicMethod;
}
else
_methodBase = dynamicMethod;
}
// This method will combine this delegate with the passed delegate
// to form a new delegate.
protected sealed override Delegate CombineImpl(Delegate? follow)
{
if (follow is null)
return this;
// Verify that the types are the same...
if (!InternalEqualTypes(this, follow))
throw new ArgumentException(SR.Arg_DlgtTypeMis);
MulticastDelegate dFollow = (MulticastDelegate)follow;
object[]? resultList;
int followCount = 1;
object[]? followList = dFollow._invocationList as object[];
if (followList != null)
followCount = (int)dFollow._invocationCount;
int resultCount;
if (!(_invocationList is object[] invocationList))
{
resultCount = 1 + followCount;
resultList = new object[resultCount];
resultList[0] = this;
if (followList == null)
{
resultList[1] = dFollow;
}
else
{
for (int i = 0; i < followCount; i++)
resultList[1 + i] = followList[i];
}
return NewMulticastDelegate(resultList, resultCount);
}
else
{
int invocationCount = (int)_invocationCount;
resultCount = invocationCount + followCount;
resultList = null;
if (resultCount <= invocationList.Length)
{
resultList = invocationList;
if (followList == null)
{
if (!TrySetSlot(resultList, invocationCount, dFollow))
resultList = null;
}
else
{
for (int i = 0; i < followCount; i++)
{
if (!TrySetSlot(resultList, invocationCount + i, followList[i]))
{
resultList = null;
break;
}
}
}
}
if (resultList == null)
{
int allocCount = invocationList.Length;
while (allocCount < resultCount)
allocCount *= 2;
resultList = new object[allocCount];
for (int i = 0; i < invocationCount; i++)
resultList[i] = invocationList[i];
if (followList == null)
{
resultList[invocationCount] = dFollow;
}
else
{
for (int i = 0; i < followCount; i++)
resultList[invocationCount + i] = followList[i];
}
}
return NewMulticastDelegate(resultList, resultCount, true);
}
}
private object[] DeleteFromInvocationList(object[] invocationList, int invocationCount, int deleteIndex, int deleteCount)
{
Debug.Assert(_invocationList is object[]);
object[] thisInvocationList = (object[])_invocationList;
int allocCount = thisInvocationList.Length;
while (allocCount / 2 >= invocationCount - deleteCount)
allocCount /= 2;
object[] newInvocationList = new object[allocCount];
for (int i = 0; i < deleteIndex; i++)
newInvocationList[i] = invocationList[i];
for (int i = deleteIndex + deleteCount; i < invocationCount; i++)
newInvocationList[i - deleteCount] = invocationList[i];
return newInvocationList;
}
private static bool EqualInvocationLists(object[] a, object[] b, int start, int count)
{
for (int i = 0; i < count; i++)
{
if (!a[start + i].Equals(b[i]))
return false;
}
return true;
}
// This method currently looks backward on the invocation list
// for an element that has Delegate based equality with value. (Doesn't
// look at the invocation list.) If this is found we remove it from
// this list and return a new delegate. If its not found a copy of the
// current list is returned.
protected sealed override Delegate? RemoveImpl(Delegate value)
{
// There is a special case were we are removing using a delegate as
// the value we need to check for this case
//
MulticastDelegate? v = value as MulticastDelegate;
if (v == null)
return this;
if (!(v._invocationList is object[]))
{
if (!(_invocationList is object[] invocationList))
{
// they are both not real Multicast
if (this.Equals(value))
return null;
}
else
{
int invocationCount = (int)_invocationCount;
for (int i = invocationCount; --i >= 0;)
{
if (value.Equals(invocationList[i]))
{
if (invocationCount == 2)
{
// Special case - only one value left, either at the beginning or the end
return (Delegate)invocationList[1 - i];
}
else
{
object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, 1);
return NewMulticastDelegate(list, invocationCount - 1, true);
}
}
}
}
}
else
{
if (_invocationList is object[] invocationList)
{
int invocationCount = (int)_invocationCount;
int vInvocationCount = (int)v._invocationCount;
for (int i = invocationCount - vInvocationCount; i >= 0; i--)
{
if (EqualInvocationLists(invocationList, (v._invocationList as object[])!, i, vInvocationCount))
{
if (invocationCount - vInvocationCount == 0)
{
// Special case - no values left
return null;
}
else if (invocationCount - vInvocationCount == 1)
{
// Special case - only one value left, either at the beginning or the end
return (Delegate)invocationList[i != 0 ? 0 : invocationCount - 1];
}
else
{
object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, vInvocationCount);
return NewMulticastDelegate(list, invocationCount - vInvocationCount, true);
}
}
}
}
}
return this;
}
// This method returns the Invocation list of this multicast delegate.
public sealed override Delegate[] GetInvocationList()
{
Delegate[] del;
if (!(_invocationList is object[] invocationList))
{
del = new Delegate[1];
del[0] = this;
}
else
{
// Create an array of delegate copies and each
// element into the array
del = new Delegate[(int)_invocationCount];
for (int i = 0; i < del.Length; i++)
del[i] = (Delegate)invocationList[i];
}
return del;
}
// Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(MulticastDelegate? d1, MulticastDelegate? d2)
{
// Test d2 first to allow branch elimination when inlined for null checks (== null)
// so it can become a simple test
if (d2 is null)
{
// return true/false not the test result https://github.com/dotnet/runtime/issues/4207
return (d1 is null) ? true : false;
}
return ReferenceEquals(d2, d1) ? true : d2.Equals((object?)d1);
}
// Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(MulticastDelegate? d1, MulticastDelegate? d2)
{
// Can't call the == operator as it will call object==
// Test d2 first to allow branch elimination when inlined for not null checks (!= null)
// so it can become a simple test
if (d2 is null)
{
// return true/false not the test result https://github.com/dotnet/runtime/issues/4207
return (d1 is null) ? false : true;
}
return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1);
}
public sealed override int GetHashCode()
{
if (IsUnmanagedFunctionPtr())
return ValueType.GetHashCodeOfPtr(_methodPtr) ^ ValueType.GetHashCodeOfPtr(_methodPtrAux);
if (_invocationCount != (IntPtr)0)
{
if (_invocationList is Delegate t)
{
// this is a wrapper delegate so we need to unwrap and check the inner one
return t.GetHashCode();
}
}
if (!(_invocationList is object[] invocationList))
{
return base.GetHashCode();
}
else
{
int hash = 0;
for (int i = 0; i < (int)_invocationCount; i++)
{
hash = hash * 33 + invocationList[i].GetHashCode();
}
return hash;
}
}
internal override object? GetTarget()
{
if (_invocationCount != (IntPtr)0)
{
// _invocationCount != 0 we are in one of these cases:
// - Multicast -> return the target of the last delegate in the list
// - Wrapper delegate -> return the target of the inner delegate
// - unmanaged function pointer - return null
// - virtual open delegate - return null
if (InvocationListLogicallyNull())
{
// both open virtual and ftn pointer return null for the target
return null;
}
else
{
if (_invocationList is object[] invocationList)
{
int invocationCount = (int)_invocationCount;
return ((Delegate)invocationList[invocationCount - 1]).GetTarget();
}
else
{
if (_invocationList is Delegate receiver)
return receiver.GetTarget();
}
}
}
return base.GetTarget();
}
protected override MethodInfo GetMethodImpl()
{
if (_invocationCount != (IntPtr)0 && _invocationList != null)
{
// multicast case
if (_invocationList is object[] invocationList)
{
int index = (int)_invocationCount - 1;
return ((Delegate)invocationList[index]).Method;
}
if (_invocationList is MulticastDelegate innerDelegate)
{
// must be a wrapper delegate
return innerDelegate.GetMethodImpl();
}
}
else if (IsUnmanagedFunctionPtr())
{
// we handle unmanaged function pointers here because the generic ones (used for WinRT) would otherwise
// be treated as open delegates by the base implementation, resulting in failure to get the MethodInfo
if ((_methodBase == null) || !(_methodBase is MethodInfo))
{
IRuntimeMethodInfo method = FindMethodHandle();
RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method);
// need a proper declaring type instance method on a generic type
if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType))
{
// we are returning the 'Invoke' method of this delegate so use this.GetType() for the exact type
RuntimeType reflectedType = (RuntimeType)GetType();
declaringType = reflectedType;
}
_methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method)!;
}
return (MethodInfo)_methodBase;
}
// Otherwise, must be an inner delegate of a wrapper delegate of an open virtual method. In that case, call base implementation
return base.GetMethodImpl();
}
// this should help inlining
[DoesNotReturn]
[System.Diagnostics.DebuggerNonUserCode]
private static void ThrowNullThisInDelegateToInstance() =>
throw new ArgumentException(SR.Arg_DlgtNullInst);
#pragma warning disable IDE0060
[System.Diagnostics.DebuggerNonUserCode]
private void CtorClosed(object target, IntPtr methodPtr)
{
if (target == null)
ThrowNullThisInDelegateToInstance();
this._target = target;
this._methodPtr = methodPtr;
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorClosedStatic(object target, IntPtr methodPtr)
{
this._target = target;
this._methodPtr = methodPtr;
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorRTClosed(object target, IntPtr methodPtr)
{
this._target = target;
this._methodPtr = AdjustTarget(target, methodPtr);
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorOpened(object target, IntPtr methodPtr, IntPtr shuffleThunk)
{
this._target = this;
this._methodPtr = shuffleThunk;
this._methodPtrAux = methodPtr;
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorVirtualDispatch(object target, IntPtr methodPtr, IntPtr shuffleThunk)
{
this._target = this;
this._methodPtr = shuffleThunk;
this._methodPtrAux = GetCallStub(methodPtr);
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorCollectibleClosedStatic(object target, IntPtr methodPtr, IntPtr gchandle)
{
this._target = target;
this._methodPtr = methodPtr;
this._methodBase = System.Runtime.InteropServices.GCHandle.InternalGet(gchandle);
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorCollectibleOpened(object target, IntPtr methodPtr, IntPtr shuffleThunk, IntPtr gchandle)
{
this._target = this;
this._methodPtr = shuffleThunk;
this._methodPtrAux = methodPtr;
this._methodBase = System.Runtime.InteropServices.GCHandle.InternalGet(gchandle);
}
[System.Diagnostics.DebuggerNonUserCode]
private void CtorCollectibleVirtualDispatch(object target, IntPtr methodPtr, IntPtr shuffleThunk, IntPtr gchandle)
{
this._target = this;
this._methodPtr = shuffleThunk;
this._methodPtrAux = GetCallStub(methodPtr);
this._methodBase = System.Runtime.InteropServices.GCHandle.InternalGet(gchandle);
}
#pragma warning restore IDE0060
}
}
target | Object | 当委托对象包装一个静态方法时,这个字段为null,当委托对象包装一个实例方法时,这个字段就是要回调方法操作的对象,这个字段要指出传给实例参数的隐形字段this |
methodptr | Inptr | 内部的整数值 |
invocationlist | Object | 构造委托链时引用一个委托数组 |
2.使用委托
委托的使用需要以下步骤:
定义委托
delegate double ParocessDelegate(double param1,double param2);
委托的定义非常类似于函数,但不带函数体,且要使用delegate关键字。委托定义需要指明委托名称以及一个返回类型和一个参数列表
声明委托类型的变量
ProcessDelegate process;
定义了委托后,就可以声明一个该委托类型的变量
初始化委托变量
process =new ProcessDelegate(Multiply);
初始化委托变量时要把一个函数(此处Multiply为一个函数的名称)引用赋给委托变量,此函数需要具有与委托相同的返回类型和参数列表。c#使用上述略显古怪的语法,使用new关键字创建一个新的委托,参数为
要引用所需的函数,这是委托赋值的一个独特语法,函数名称是不带括号的
还可以用另一种略微简单的语法
process = Muiltiply;
有了引用函数的委托变量之后,我们就可以用委托变量调用Muiltiply函数;也可以把委托变量传递给其他函数
process (param1,param2);
namespace Delegate
{
public delegate int Call(int num1, int num2);//第一步:定义委托类型
class SimpleMath
{
// 乘法方法
public int Multiply(int num1, int num2)
{
return num1 * num2;
}
// 除法方法
public int Divide(int num1, int num2)
{
return num1 / num2;
}
}
}
class Test
{
static void Main(string[] args)
{
Call objCall;//第二步:声明委托变量
// Math 类的对象
SimpleMath objMath = new SimpleMath();
// 第三步:初始化委托变量,将方法与委托关联起来
objCall = new Call(objMath.Multiply);
objCall += objMath.Divide;//向委托增加一个方法
//objCall -= objMath.Divide;//向委托减去一个方法
// 调用委托实例,先执行objMath.Multiply,然后执行objMath.Divide
int result = objCall(5, 3);
System.Console.WriteLine("结果为 {0}", result);
Console.ReadKey();
}
}
注意事项:
- 委托可以调用多个方法,即一个委托变量可以引用多个函数,称为多路广播
- 可以使用+=和-=运算符实现方法的增加和减少
- 无返回值的委托,引用了多少个方法就会执行多少个方法。有返回值的委托同样会执行多个引用的方法,但返回的值是最后一个方法的返回值