• C#入门(3)


    C#入门(3)

    Delegates, Events, Lambda Expressions

    最早的windows是使用c风格的函数指针来进行callback的,但是这样仅仅传递了一个内存中的地址,无法包含更多的信息,如类型安全等,而且容易引发crash.

    所以.Net平台下的delegate可以指向静态方法或者是对象方法,一般包含三种重要信息:

    1. 需要调用的方法的地址
    2. 方法的参数
    3. 方法的返回值

    代理可以支持同步方法和异步方法:
    对于一个delegate,首先编译器会生成一个seal的类.具体如下:

    public delegate string MyDelegate(bool a, bool b, bool c);
    
    sealed class MyDelegate : System.MulticastDelegate
    {
    	public string Invoke(bool a, bool b, bool c);
    	public IAsyncResult BeginInvoke(bool a, bool b, bool c,AsyncCallback cb, object state);
    	public string EndInvoke(IAsyncResult result);
    }
    
    // This is only pseudo-code!
    public sealed class DelegateName : System.MulticastDelegate
    {
    	public delegateReturnValue Invoke(allDelegateInputRefAndOutParams);
    	public IAsyncResult BeginInvoke(allDelegateInputRefAndOutParams,AsyncCallback cb, object state);
    	public delegateReturnValue EndInvoke(allDelegateRefAndOutParams,IAsyncResult result);
    }
    

    在生成的类中的三个方法中,Invoke()是负责同步(synchronized)的,该方法在使用正确的语法时,不需要显式调用.而剩下的两个BeginInvoke()和EndInvoke()是负责异步的(asynchronized),注意这里的BeginInvoke()后面会自动增加两个参数,一个是AsyncCallback,一个是object;而EndInvoke()的返回值则是delegate的返回值,参数则是BeginInvoke()的返回值.但是当使用out或者ref修饰的参数时,这样的参数也会传递给EndInvoke().

    所以使用delegate声明,其实是继承了System.MulticastDelegate类和System.Delegate类.但是在程序中不能够显式继承自这两个类.下面给出了这两个类的部分:

    public abstract class MulticastDelegate : Delegate
    {
    	// Returns the list of methods "pointed to."
    
    	public sealed override Delegate[] GetInvocationList();
    	// Overloaded operators.
    	public static bool operator ==(MulticastDelegate d1, MulticastDelegate d2);
    	public static bool operator !=(MulticastDelegate d1, MulticastDelegate d2);
    
        // Used internally to manage the list of methods maintained by the delegate.
    	private IntPtr _invocationCount;
    	private object _invocationList;
    }
    
    public abstract class Delegate : ICloneable, ISerializable
    {
    	// Methods to interact with the list of functions.
    	public static Delegate Combine(params Delegate[] delegates);
    	public static Delegate Combine(Delegate a, Delegate b);
    	public static Delegate Remove(Delegate source, Delegate value);
    	public static Delegate RemoveAll(Delegate source, Delegate value);
    	// Overloaded operators.
    	public static bool operator ==(Delegate d1, Delegate d2);
    	public static bool operator !=(Delegate d1, Delegate d2);
    
    	// Properties that expose the delegate target.
    	public MethodInfo Method { get; }
    	public object Target { get; }
    }
    

    下表给出具体属性的含义:

    Member Meaning
    Method This property returns a System.Reflection.MethodInfo object that represents details of a static method maintained by the delegate.
    Target If the method to be called is defined at the object level (rather than a static method), Target returns an object that represents the method maintained by the delegate. If the value returned from Target equals null, the method to be called is a static member.
    Combine() This static method adds a method to the list maintained by the delegate. In C#, you trigger this method using the overloaded += operator as a shorthand notation.
    GetInvocationList() This method returns an array of System.Delegate objects, each representing a particular method that may be invoked.
    Remove() RemoveAll() These static methods remove a method (or all methods) from the delegate’s invocation list. In C#, the Remove() method can be called indirectly using the overloaded -= operator.

    Combine()是当给delegate增加回调函数时用的,调用+=会隐式调用Combine(),

    使用delegates:
    一般使用delegates的步骤为:

    1. 定义一种新的delegates类型,来支持回调
    2. 在使用delegates的类中定义一个该delegates的成员变量,可以是private也可以是public
    3. 定义一个辅助函数来使得调用者可以方便的调用回调
    4. 实现函数,在其中正确地调用delegates变量

    Tips:

    在c#中的界面开发中,由于父级控件的属性设置对于子级控件是有影响的,因此对于多级嵌套的层级控件,必须定义好add的顺序,先将后继控件加载然后加入到前级控件和先加载自身,然后加载后继控件是不同的。A-1-B-2-C和A-2-B-1-C,如这个表达式,ABC依次为嵌套关系。数字代表加载顺序。

    这里的关键因素是一个属性,一般是tabControl或者是tabPage有的,叫AutoScaleMode,默认的是根据Font来进行改变,因此当父级元素和子级元素中的Font设置不一样,甚至是设置的一样,但是加入时仍然会按照字体的大小进行缩放处理.所以将该属性设为none可以避免不必要的麻烦.
    这个Tips如果算是Bug,应该解了.

  • 相关阅读:
    HIVE(2) 之 常用函数
    HIVE的Shell操作
    HIVE常用函数(1)聚合函数和序列函数
    版本控制系统之SVN和GIT的区别
    【PyQt5】信号与槽+装饰器定义槽函数
    【PyQt5】信号与槽+多线程
    【PyQt5】信号与槽用法进阶
    【PyQt5】信号与槽用法入门
    【python之路】【5、函数学习】带装饰器的函数作业【老男孩第2期全栈】
    【python之路】【4、文件操作】数据类型、文件操作-作业 用文件储存三级菜单并执行
  • 原文地址:https://www.cnblogs.com/putuotingchan/p/8628721.html
Copyright © 2020-2023  润新知