zoukankan      html  css  js  c++  java
  • 进入快速委托通道

    笨拙的委托语法

    C#1中,先写好一连串事件处理程序,然后写new EventHandler。
    #region 5-1
    Button button = new Button();
    button.Text = "Click me";
    button.Click += new EventHandler(LogPlainEvent);//点击触发
    button.KeyPress += new KeyPressEventHandler(LogKeyEvent);
    button.KeyPress += LogKeyEvent;//隐式转换
    button.MouseClick += new MouseEventHandler(LogMouseEvent);//鼠标单击时触发
    #endregion
    #region 5-1
    static void LogPlainEvent(object sender, EventArgs e)
    {
    MessageBox.Show("LogPlain");
     
    }
     
    static void LogKeyEvent(object sender, KeyPressEventArgs e)
    {
    MessageBox.Show("LogKey");
     
    }
     
    static void LogMouseEvent(object sender, MouseEventArgs e)
    {
    MessageBox.Show("LogMouse");
     
    }
    #endregion
    方法组转换
    C#2支持从方法组到一个兼容类型的隐式转换。方法组就是一个方法名,它可以添加一个目标。
    协变性和逆变性
    委托参数的逆变性
    Button button2 = new Button();
    button2.Click += LogPlainEvent;
    button2.KeyPress += LogPlainEvent;//转换和逆变性
    button2.MouseClick += LogPlainEvent;
    static void LogPlainEvent(object sender, EventArgs e)//处理所有事件
    {
    MessageBox.Show("LogPlain");
     
    }
    委托返回类型的协变性
    #region 5-3演示委托返回类型的协变性
    StreamFactory factory = GenerateSampleData;//利用协变性转换方法组
    using (Stream stream = factory())
    {
    int data;
    while ((data = stream.ReadByte()) != -1)//调用委托以获得Stream
    {
    Console.WriteLine(data);
    }
    }
    #endregion
    #region 5-3
    static MemoryStream GenerateSampleData()//声明返回MemoryStream的方法
    {
    byte[] buffer = new byte[16];
    for (int i = 0; i < buffer.Length; i++)
    {
    buffer[i] = (byte)i;
    }
    return new MemoryStream(buffer);
    }
    #endregion
    不兼容风险
    #region 5-4
    public class Derived : Snippet
    {
    public void CandidateAction(object x)
    {
    Console.WriteLine("Derived.CandidateAction");
    }
    }
    public class Snippet
    {
    public void CandidateAction(string x)
    {
    Console.WriteLine("Snippet.CandidateAction");
    }
    }
    #endregion
    #region 5-4C#1和C#2的重大变化
    Derived x = new Derived();
    SampleDelegate factory = new SampleDelegate(x.CandidateAction);
    factory("text");
    #endregion
    使用匿名方法的内联委托操作

    #region 5-5将匿名方法用于Action<T>委托类型
    Action<string> printReverse = delegate(string text)//使用匿名方法创建Action<string>
    {
    char[] chars = text.ToCharArray();
    Array.Reverse(chars);
    Console.WriteLine(new string(chars));
    };
     
    Action<int> printRoot = delegate(int number)
    {
    Console.WriteLine(Math.Sqrt(number));
    };
     
    Action<IList<double>> printMean = delegate(IList<double> numbers)
    {
    double total = 0;
    foreach (double value in numbers)
    {
    total += value;
    }
    Console.WriteLine(total / numbers.Count);
    };
    printReverse("Hello world");
    printRoot(2);
    printMean(new double[] { 1.5, 2.5, 3, 4.5 });
    #endregion
    逆变性不适用匿名方法:必须指定和委托类型完全匹配的参数类型。
    在值类型中编写匿名方法时,不能在内部引用this,引用类型中则没有这个限制。
    IL为源代码中的每个匿名方法都创建了一个方法:编译器将在已知类(匿名方法所在类)内部生成一个方法,并创建委托实例时操作
    #region 5-6代码精简的极端例子
    List<int> x = new List<int>();
    x.Add(5);
    x.ForEach(delegate(int n)
    { Console.WriteLine(Math.Sqrt(n)); }
    );
     
    x.ForEach(delegate(int n)
    { Console.WriteLine(Math.Sqrt(n)); }
    );
    #endregion
    匿名方法的返回值
    #region 5-7从匿名方法返回一个值
    Predicate<int> isEven = delegate(int x) { return x % 2 == 0; };
    Console.WriteLine(isEven(1));
    #endregion
    编译器只需要检查所有返回类型都兼容于委托类型声明的返回类型
    #region 5-8用匿名方法简单的排序文件
    SortAndShowFiles("Sorted by name:", delegate(FileInfo f1, FileInfo f2)
    { return f1.Name.CompareTo(f2.Name); });
     
    SortAndShowFiles("Sorted by Length:", delegate(FileInfo f1, FileInfo f2)
    { return f1.Length.CompareTo(f2.Length); });
    #endregion
    #region 5-8
    static void SortAndShowFiles(string title, Comparison<FileInfo> sortOrder)
    {
    FileInfo[] files = new DirectoryInfo(@"c:").GetFiles();
     
    Array.Sort(files, sortOrder);
    Console.WriteLine(title);
    foreach (FileInfo file in files)
    {
    Console.WriteLine(" {0} ({1} bytes)", file.Name, file.Length);
    }
    }
    #endregion
    忽略委托参数
    #region 5-9使用忽略了参数的匿名方法来订阅事件
    Button button = new Button();
    button.Text = "Click me";
    button.Click += delegate { MessageBox.Show("LogPlain"); };
    button.KeyPress += delegate { MessageBox.Show("LogKey"); };
    button.MouseClick += delegate { MessageBox.Show("LogMouse"); };
    #endregion
    匿名方法中捕获变量
    定义闭包和不同类型的变量
    闭包:一个函数除了能通过提供给它的参数交互之外,还能痛环境进行更大程度的互动
    外部变量:指作用域内包括匿名方法的局部变量或参数。在类的实例成员的匿名方法中,this引用也被认为是一个外部变量。
    捕获外部变量:在匿名方法内部使用的外部变量。
    #region 5-10不同种类的变量和匿名方法的关系
    void EnclosingMethod()
    {
    int outerVariable = 5;//外部变量
    string capturedVariable = "captured";//被匿名方法捕获的外部变量
     
    if (DateTime.Now.Hour == 23)
    {
    int normalLocalVariable = DateTime.Now.Minute;//普通方法的局部变量,不是外部变量,作用域中没有匿名方法
    Console.WriteLine(normalLocalVariable);
    }
     
    MethodInvoker x = delegate()
    {
    string anonLocal = "local to anonymous method";//匿名方法的局部变量
    Console.WriteLine(capturedVariable + anonLocal);//捕获外部变量
    };
    x();
    }
    #endregion
    捕获变量的行为
    被匿名方法捕获到的是变量,而不是创建委托类型时该变量的值。
    #region 5-11从匿名方法内外访问一个变量
    string captured = "before x is created";
    MethodInvoker x = delegate//创建委托实例不会导致执行
    {
    MessageBox.Show(captured);//directly before x is invoked
    captured = "changed by x";
    };
     
    captured = "directly before x is invoked";
    x();//changed by x
     
    MessageBox.Show(captured);
     
    captured = "defore second invocation";
    x();//defore second invocation
    #endregion
    捕获变量的用处
    能简化避免专门创建一些类来储存一个委托需要处理的信息
    捕获变量的延长生存期
    #region 5-12
    static MethodInvoker CreateDelegateInstance()//拥有对该类的一个实例引用
    {
    int counter = 5;
    MethodInvoker ret = delegate//拥有对该类的一个实例引用
    {
    MessageBox.Show(Convert.ToString(counter));
    counter++;//用一个额外的类来捕获变量,捕获变量的实例
    };
    ret();
    return ret;
    }
    #endregion
     
    #region 5-12捕获变量的生存期延长
    MethodInvoker x = CreateDelegateInstance();
    x();
    x();
    #endregion
    局部变量实例化
    #region 5-13使用多个委托来捕捉多个变量实例
    List<MethodInvoker> list = new List<MethodInvoker>();
     
    for (int index = 0; index < 5; index++)
    {
    int counter = index * 10;//实例化counter
    list.Add(delegate//创建5个委托实例
    {
    MessageBox.Show(Convert.ToString(counter));//直接打印index * 10结果都为50,初始化变量只被实例化一次
    counter++;
    }
    );
    }
     
    foreach (MethodInvoker t in list)
    {
    t();//执行5个委托实例
     
    }
    list[0]();//1
    list[0]();//2
    list[0]();//3
     
    list[1]();//11
    #endregion
    共享和非共享的变量混合使用。
    生成一个额外类,它包含外部变量,还生成另一个额外类,它包含内部变量和对第一个额外类的引用。根本上,包含一个捕获变量的每个作用域都有它自己的类型。
  • 相关阅读:
    pku2992 Divisors
    pku3090 Visible Lattice Points
    pku3615 Cow Hurdles
    禁止 verifier.dll 监控程序
    运行ogreSDK的samples
    #pragma pack(n) 啥时候可以不再忘记?
    游戏开发流程图。
    希望可以尽快的写篇自己的成果。
    windows与OS X下的std::string
    VS2008鼠标右键不灵敏,TFS的Local Path无法打开对应文件夹
  • 原文地址:https://www.cnblogs.com/Tan-sir/p/5169206.html
Copyright © 2011-2022 走看看