• 进入快速委托通道


    笨拙的委托语法

    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
    共享和非共享的变量混合使用。
    生成一个额外类,它包含外部变量,还生成另一个额外类,它包含内部变量和对第一个额外类的引用。根本上,包含一个捕获变量的每个作用域都有它自己的类型。
  • 相关阅读:
    spring @Transactional 事务注解
    vue 父子组件的方法调用
    spring boot使用TestRestTemplate集成测试 RESTful 接口
    JS实现网站内容的禁止复制和粘贴、另存为
    vue把localhost改成ip地址无法访问—解决方法
    spring mvc spring boot 允许跨域请求 配置类
    JIRA安装过程中链接mysql的问题!
    vue开发中v-for在Eslint的规则检查下出现:Elements in iteration expect to have 'v-bind:key' directives
    Linux进程启动/指令执行方式研究
    反弹Shell原理及检测技术研究
  • 原文地址:https://www.cnblogs.com/Tan-sir/p/5169206.html
Copyright © 2020-2023  润新知