ITPub博客

首页 > 数据库 > Oracle > C#委托的应用

C#委托的应用

Oracle 作者:cuiyuheng 时间:2013-10-29 11:27:06 0 删除 编辑

.Net delegate类型:
    委托跟回调函数是很有渊源的。回调其实跟通知机制有关,考虑这样一个基本的事件序列:a对象调用了b对象的某个方法,希望b对象在其方法完成之时调用a对象的某个方法。要实现这样的过程,要求b对象持有a对象的引用(引用一般作为b 对象方法的参数传入),且“知道”a对象的那个特定方法。这个方法就是我们说的那个回调函数。
    本质上,.net的委托类型是一种类型安全的指向方法的对象(c++中如函数指针)亦或是指向一系列方法的对象。所谓类型安全指:类型必须匹配,变量或引用不能指向一个不是该类的对象,类型安全由编译器保障,违反类型安全编译时会给出提示。对函数指针而言,就是返回值,入口参数的数目,类型和顺序应一致。委托一般都是滞后调用,编写委托实现的人一般不知道具体何时该方法被调用。不象传统的C++方法指针,.net的委托是类且具有内建支持,可进行异步和广播式的调用。

    委托跟事件event可自然的契合,一般是事件激发导致委托被调用。
    委托对象含有三个重要的信息:

    1〉被调用方法的地址;

    2〉此方法的参数(如果有的话);

    3> 方法的返回值(如果有的话).不同于C++函数指针,.net委托既可指向实例方法也可指向静态方法.
一旦委托被创建且提供了足够的信息,便可在运行时调用它指向的方法.每个委托都可被异步和同步的调用,此点简化了编程工作:使得我们不用手工创建和管理线程对象,就可以在第二个线程中执行我们的方法.
   C#中创建委托使用delegate关键字,委托名可以是任何你认为有意义的词.但必须使你的委托匹配你想指向的方法的签名.当C#的编译器处理委托类型时,会自动地生成一个密封(sealed)类,该类继承自System.MulticastDelegate.(这个类的父类是System.Delegate),此类提供了必要的基础结构便于委托持有一个方法的列表,这些方法会在后期的某个时间被调用
    通过查看中间语言代码il(用ildasm.exe),可发现编译器会为委托类产生三个公共方法.Invoke();BeginInvoke()和EndIvoke();Invoke()是主要的方法,用于调用委托维护的每个方法.向所有同步调用一样,方法会阻塞调用者直到它执行完毕.Invoke方法也不必显式的调用,它工作于后台.后两个方法需配合使用用于异步执行委托指向的方法. 他们会在独立的线程中执行.
    委托的构造方法: public TypeOfReturn MyDelegate(object target,uint fuctionAddress),可以看出它需要目标对象,和目标方法的函数地址.这个很易理解,所有方法的调用都遵循object.functionName(),的格式.不过还缺少:参数和返回 值.他们在上面提到的三个方法中给出: public TypeOfReturnValue Invoke([TypeOfParameter ParaX]*); //其中TypeOfReturnValue是返回值的类型,中括号里的是可不出现或可出现多个的参数列.异步方法对:public IAsyncResult BeginInvoke([TypeOfParameter ParaX]*);public TypeOfReturnValue EndInvoke(IAsyncResult result);可看出不同处:BeginInvoke先返回一个中间类型,在EndInvoke中才是目标返回值的类型;    Invoke 方法给人这样的感觉: A--->C ; 而BeginIvoke和EndInvoke: A---->B B---->C 等价于A----C .
    引入中间过程的原因是什么呢? 这个 问题以后在讨论吧:它跟异步执行有关,见后面的文章。下面是委托由编译器产生的伪码表示:哈尔滨网站设计
public sealed class DelegateName : System.MulticastDelegate
{
public DelegateName (object target, uint functionAddress);
public delegateReturnValue Invoke(allDelegateInputRefAndOutParams);
public IAsyncResult BeginInvoke(allDelegateInputRefAndOutParams,
AsyncCallback cb, object state);
public delegateReturnValue EndInvoke(allDelegateRefAndOutParams,
IAsyncResult result);
}
    综述:C#委托,编译器会为其对应地产生一个密封(sealed)类,该类有三个核心方法,这些方法的参数和返回值基于委托的定义。

    关键字delegate使得你自定义的委托是一个(“is-a”)MulticastDelegate.所有用该关键字修饰的定义类型都是MulticastDelegate的子类,而该类又是Delegate的子类:(public abstract class Delegate : ICloneable, ISerializable)
以下是我的简单学习测试:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DelegateTest
{
  

    public delegate string MyDelegateType(string firstArg,string secondArg);//创建了一个委托

    public class SomeType {
   
    public static string ClassMethodX(string str1,string str2){
        System.Console.WriteLine("enter the static method <--");
        try
        {
            System.Console.WriteLine("一些对参数的处理工作.......");
            return String.Format("parameter1:{0} and Parameter2{1} come from a static Method", str1, str2);
        }
        finally {
            System.Console.WriteLine("end the static method-->");
        }
    }


    public string InstanceMethodX(string str1,string str2) {

        System.Console.WriteLine("enter the instance method <--");
        try
        {

            System.Console.WriteLine("一些对参数的处理工作.......");
            return String.Format("parameter1:{0} and Parameter2{1} come from a instance Method", str1, str2);
        }
        finally
        {
            System.Console.WriteLine("end the instance method-->");
        }
   
   
   
    }

    }


//程序入口:


    class Program
    {
        static void Main(string[] args)
        {
            MyDelegateType myDelegate = new MyDelegateType(SomeType.ClassMethodX);//创建一个委托,帮定到一个静态方法上

            System.Console.WriteLine("开始调用委托");
            System.Console.WriteLine(myDelegate("参数一","参数二"));
            System.Console.WriteLine("结束调用委托");

            SomeType aUDTType = new SomeType();//实例化一个自定义的类实例(UDT--表示用户定义类型)
            myDelegate += new MyDelegateType(aUDTType.InstanceMethodX);
            System.Console.WriteLine("开始调用委托");
            System.Console.WriteLine(myDelegate("参数一", "参数二"));
            System.Console.WriteLine("结束调用委托");


            System.Console.ReadLine();

        }
    }
}

    再次重申:委托是可指向方法或方法列的对象,是安全的方法指针。
    任何与委托格式匹配的方法(静态的或实例的),都可由委托指向(作为构造委托的参数传递到构造方法中去),只要参数信息(类型,数目,顺序)和返回值类型匹配,就可用于构造委托,与方法的名字没有任何关系。委托的内部维护了一个集合,估计是一ArrayList(仅是猜测啊!不过一般不必太在意到底是具体何种集合)。使用+=/combine()方法可将新的委托添加到原有委托上,-=/Remove()会从队列中摘掉一个委托成员,至于,委托的加入顺序与其执行顺序,留给朋友们了^-^;想想Oracle的

    触发器的添加和执行顺序:(后添加的先执行).哈尔滨网站设计

    委托的调用:用委托的实例名,加括号并传入参数即可。相当委托的实例名就是一个方法名,按方法的调用方式来就行。(底层其实

    调用的是实例的Invoke方法,此点对程序员透明,用ildasm.exe可查看)当然也显式调用Invoke():myDelegateInstance

(argList);和myDelegateInstance.Invoke(argList);等效果,不过多用前者形式。

    委托内部探查:
foreach (Delegate d in delegateObj.GetInvocationList())
{
Console.WriteLine("Method Name: {0}", d.Method);
Console.WriteLine("Type Name: {0}", d.Target);
}

    委托是一种类型,他可如常规类定义的出现位置那样出现,可以在类内部声明----这也是最常用的最自然的方式,编译器为我们产生的

    对应类型就是嵌套类了,当然也有通用的委托如:处理GUI按钮单击,拖拽,键盘敲击等的统一的委托类,你会发现他们的事件处理

    方法的参数和返回类型都很一致。
    委托作为成员:在你定义了一个委托后,可声明委托的变量来作为类的成员(方法变量成员)。如同常规的类成员一样,可以用访问修饰符去修饰它,也可以声明多个同类型委托的实例,每个实例在不同的情况下使用(委托的调用参考上面所述)。当委托是私有成员的时候,可能需要你提供公有的注册和注销的接口,但是是类型安全的常规解决方案(成员私有访问,成员的方法签名为公有)。哈尔滨软件开发
    一点注意:在调用委托时最好有非空的判断逻辑,不然可能引发NullReferenceException异常。
委托的多播调用:委托天然具有多播功能,其+=操作可往委托持有的列表中添加一个新的委托,+=是Combine()方法的简明方式,

也可直接调用其Combine(),不过用+=似乎更符合C# 的习惯法.对应的-=操作(Remove()的简明用法)同此理.需注意的是,-=操作的参数

需有匹配的签名方法.并非实际的那个委托实例被删除.其实不必持有已合并的委托的实例(当然第一个委托的实例还是需要的),一般

用myExistDelegate += new MyDelegate(someObj.method()).删除时可用myExistDelegate -= new MyDelegate(someObj.method());

只要方法签名匹配即可.
委托可被用作方法的参数传递,就像其他的.net类型一样.
诡异的用法:
像下面的委托的定义:public delegate SomeType SomeDelegate(.....);此委托是一个可返回某类型SomeType的对象,任何可返回

SomeType且参数信息匹配的方法都可用于实例化一个SomeDelegate.设想一个方法返回的是SomeType的子类型对象,且参数信息匹配

SomeDelegate的参数信息.是否可用于实例化一个SomeDelegate呢?.net2.0之前,是不可以的,必须再创建一个委托类型,其返回类型是

SomeType 的子类型.参考经典的继承法则,创建一个委托类型,它可指向任何返回SomeType或其子类的方法(方法的签名匹配委托定义)
这是很自然的.术语称为relaxed delegates----松弛委托.考虑经典的工厂方法(Gof23中设计模式的一种),它的特点是否跟此特征很

像呢!!!;
创建泛型委托:
泛型编程或模板编程,是更抽象的编程,模板类可称为是类的蓝图.用模版你甚至可以创建出类.(参考说法: 类是对象的蓝图,类是对象

的构造工厂)...比如常规的集合类型,多有模板版本和常规的版本, System .Collections.Generic.LinkedList,模版版本的集合

需要传入类型去替换T.如System.Collections.Generic.LinkedList strList = new LinkedList();便是创建了一

个只能存储字符型的连接链表.委托也可有模版式的,如: public delegate void MyGenericDelegate(T arg);
以上就是一个泛型委托,它是一个可返回空的委托模版,可用它来创建一个委托如: MyGenericDelegate intTarget =
new MyGenericDelegate(IntTarget);其中intTarget就是参数是一个int型且返回值是void的方法.这里假设intTarget是静态方

法.可用非泛化模拟泛型.只要让所有出现类型的地方用object类型就可达到泛型的效果.如:public delegate void MyDelegate

(object arg);和上面的模版版本效果一样,不过非类型安全而已.因为泛类型System.Object可指向任何类型的实例.而非上面的参数哈尔滨网站制作只可是int型.模版实例化过程:把T用具体类型换掉.之后的使用过程会得到编译器的类型检查帮助. 以Object类型作为参数的编程常

需要具体的型别检查逻辑,而使用模板可避免此问题.

<!-- 正文结束 -->

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/21375724/viewspace-1117056/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2009-04-13