C#知识点-15(匿名函数、使用委托进行窗体传值、反射)

时间:2024-02-23 09:30:57

匿名函数

概念:没有名字的函数,一般情况下只调用一次。它的本质就是一个方法,虽然我们没有定义这个方法,但是编译器会把匿名函数编译成一个方法

    public delegate void Del1();//无参数无返回值的委托
    public delegate void Del2(string name);//有参数无返回值的委托
    public delegate string Del3(string s,int n);//有参数有返回值的委托
    internal class Program
    {
        static void Main(string[] args)
        {
            Del1 del1 = delegate ()
            {
                Console.WriteLine("无参数无返回值的匿名函数");
            };
            del1.Invoke();
            Console.ReadKey();
        }
    }

我们可以使用lambda表达式更简洁地定义一个匿名函数

            Del1 del1 = () => { Console.WriteLine("无参数无返回值的lambda表达式"); };
            del1.Invoke();//调用
            Console.ReadKey();

当lambda表达式中参数列表只有一个参数时,括号可以省略

            Del2 del2 = msg => { Console.WriteLine("hello" + msg); };
            del2.Invoke("world" + "有参数无返回值的lambda表达式");
            Console.ReadKey();

匿名函数定义的参数列表的参数类型,是不能省略的

            Del3 dle3 = (string s1, int n1) => { return "有参数有返回值的lambda表达式"; };
            string res = dle3.Invoke("1", 1);
            Console.WriteLine(res);

泛型委托

之前我们写的委托都是需要自己定义委托的参数和返回值,而.NET框架为我们封装了泛型委托框架,让我们不用再声明委托,可以直接使用。分别为Action委托,Func委托。

Action委托:
不带返回值的委托,可以有参数,也可以没有参数

            Action action = () => { Console.WriteLine("无参无返回值的委托"); };
            action();//直接调用
            action.Invoke();//间接调用

            Action<string,int> action2 = (a,b)=> { Console.WriteLine("姓名为{0}的人,年龄为{1}",a,b); };
            action2.Invoke("张三",18);
            Console.ReadKey();

Func委托:
带返回值的委托


            //如果Func尖括号里只有一个参数类型,就表示返回值就是这个类型
            Func<int> func = () => { return 100; };
            int a = func.Invoke();
            Console.WriteLine(a);

            //需要两个整数类型的参数,以及一个string类型的返回值
            Func<int, int, string> func2 = (c, d) => { Console.WriteLine(c); Console.WriteLine(d); return "hello world"; };
            string res = func2.Invoke(10, 20);
            Console.WriteLine(res);

使用委托进行窗体传值

1、先创建两个窗体对象,添加所需控件


2、当点击form1按钮时,将textbox里的值传递给form2
 

namespace 委托_窗体传值
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //创建一个form2对象,通过form2的构造函数将窗体1的文本框的值传递给窗体2
            Form2 form2 = new Form2(textBox1.Text.Trim());
            //将窗体2展示出来
            form2.Show();
        }
    }
}
namespace 委托_窗体传值
{
    public partial class Form2 : Form
    {
        public Form2(string msg)//窗体2的构造函数,每回创建窗体2对象的时候都会执行构造函数初始化。通过参数接收窗体一传递过来的值
        {
            InitializeComponent();
            textBox1.Text = msg;//将接收到的值展示到窗体2的文本框上
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }
    }
}

3、当点击form2的按钮时,将窗体2中的值传递给窗体1
 

    public partial class Form2 : Form
    {
        string _msg;//字段存储窗体二收到的消息
        Action<string> _action;
        public Form2(string msg,Action<string> action)//窗体2的构造函数,每回创建窗体2对象的时候都会执行构造函数初始化。通过参数接收窗体一传递过来的值
        {
            InitializeComponent();
            //textBox1.Text = msg;//将接收到的值展示到窗体2的文本框上
            this._msg = msg;
            this._action = action;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //调用ShowMsg,将值传递给窗体1
            this._action.Invoke(textBox1.Text.Trim());
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            //窗体加载的时候,把数据赋值给文本框
            textBox1.Text = this._msg;
        }
    }
namespace 委托_窗体传值
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //创建一个form2对象,通过form2的构造函数将窗体1的文本框的值传递给窗体2
            Form2 form2 = new Form2(textBox1.Text.Trim(),ShowMsg);
            //将窗体2展示出来
            form2.Show();
        }
        void ShowMsg(string msg)
        {
            textBox1.Text = msg;
        }
    }
}

多播委托

概念:让一个委托对象,指向多个方法

    internal class Program
    {
        public delegate void Del();
        static void Main(string[] args)
        {
            Del del = M1;
            del += M2;
            del += M3;
            del += M4;
            del -= M5;
            del.Invoke();
            Console.ReadKey();

        }
        static void M1()
        {
            Console.WriteLine("我是M1");
        }
        static void M2()
        {
            Console.WriteLine("我是M2");
        }
        static void M3()
        {
            Console.WriteLine("我是M3");
        }
        static void M4()
        {
            Console.WriteLine("我是M4");
        }
        static void M5()
        {
            Console.WriteLine("我是M5");
        }
    }

运行结果

反射

概念:反射就是动态获取程序集中的元数据(提供程序集的类型信息)的功能

    internal class Program
    {
        static void Main(string[] args)
        {
            //Type
            //获取类型的类型:元数据
            //获取类型的Type有两种方式
            //1、创建了Person对象
            //Person p = new Person();
            //Type type = p.GetType();
            //2、没有创建Person对象
            Type type = typeof(Person);  //typeof后面放的是数据类型,不能放对象
            //GetMembers()获取type反射出来所有的类型中的公共成员
            MemberInfo[] mi = type.GetMembers(BindingFlags.Instance|BindingFlags.NonPublic);
            foreach (var item in mi)
            {
                Console.WriteLine(item.Name);
            }

            Console.ReadKey();

        }
    }

    class Person
    {
        public Person()
        {

        }
        private string _name;
        public int Age { get; set; }
        public void SayHi()
        {
            Console.WriteLine("实例方法");
        }
        public static void StaticSayHi()
        {
            Console.WriteLine("静态方法");
        }
        public Person(string name, int age)
        {
            this._name = name;
            this.Age = age;
        }
        public Person(int age)
        {
            this.Age = age;
        }
    }

反射程序集中的元数据

    internal class Program
    {
        static void Main(string[] args)
        {
            //1、先获取要反射数据的程序集
            //注意:就把ass这个程序集对象,当成是DLL类库
            Assembly ass = Assembly.LoadFile(@"C:\Users\ThinkPad\source\repos\DLL_Test\bin\Debug\DLL_Test.dll");
            //2、获取程序集中定义的数据类型/成员 GetTypes获取的成员包括public和internal修饰的
            //Type[] types = ass.GetTypes();
            //GetExportedTypes();获取所有被public修饰的成员
            //Type[] types = ass.GetExportedTypes();
            //foreach (var item in types)
            //{
            //    Console.WriteLine(item.Name);
            //}
            //GetType():在类型的名字前面,必须加上命名空间
            Type type = ass.GetType("DLL_Test.Person");

            //class:类
            //Method:方法
            //field:字段
            //Property:属性
            //Instance:实例的
            //static:静态的
            //Assembly:程序集
            //Type:类型
            //Exported:公开的
            //Member:成员
            //Parameter:参数
            //Constructor:构造函数
            //GetMembers()获取类型中定义的所有公开成员
            //MemberInfo[] mi = type.GetMembers(BindingFlags.Instance | BindingFlags.NonPublic);
            //foreach (var item in mi)
            //{
            //    Console.WriteLine(item.Name);
            //}

            //3、获取类型中定义的所有的方法
            //MethodInfo[] mi = type.GetMethods();
            //foreach (var item in mi)
            //{
            //    Console.WriteLine(item.Name);


            //    //Console.WriteLine(item.ReturnParameter.Name);
            //    Console.WriteLine(item.ReturnType); //获取返回值的类型
            //    Console.WriteLine("==============================");
            //}

            4、获取类型中定义的所有构造函数
            //ConstructorInfo[] ci = type.GetConstructors();
            //foreach (var item in ci)
            //{
            //    Console.WriteLine(item.Name);
            //    ParameterInfo[] pi = item.GetParameters();
            //    foreach (var item2 in pi)
            //    {
            //        Console.WriteLine(item2.Name);
            //        //获取参数类型
            //        Console.WriteLine(item2.ParameterType);
            //        Console.WriteLine("==============================================");
            //    }
            //}


            //5、获取数据类型中定义的所有属性
            //PropertyInfo[] pi = type.GetProperties();
            //foreach (var item in pi)
            //{
            //    Console.WriteLine(item.Name);
            //}

            //6、获取数据类型中定义的所有字段
            //FieldInfo[] fi = type.GetFields(BindingFlags.Instance|BindingFlags.NonPublic);
            //foreach (var item in fi)
            //{
            //    Console.WriteLine(item.Name);
            //}


            //7、调用静态方法
            //MethodInfo[] mi = type.GetMethods(BindingFlags.Static | BindingFlags.Public); 
            //foreach (var item in mi)
            //{
            //    Console.WriteLine(item);
            //}

            //MethodInfo mi = type.GetMethod("StaticSayHi");
            调用
            参数1:表示实例对象,调用静态方法,可以不提供,给null值即可。
            参数2:表示方法的参数,必须以object数组的形式提供。
            //object res = mi.Invoke(null, new object[] { "world" });
            //Console.WriteLine(res);

            8、调用实例方法
            //MethodInfo mi = type.GetMethod("InstanceSayHi");
            动态的创建对象 CreateInstance帮我们执行构造函数,创建对象
            //object o = Activator.CreateInstance(type);
            //mi.Invoke(o, null);

            //9、调用重载方法 new Type[] { typeof(int), typeof(int) } 来匹配重载
            //MethodInfo mi = type.GetMethod("Add", new Type[] { typeof(int), typeof(int) });
            //object o = Activator.CreateInstance(type);
            //object res = mi.Invoke(o, new object[] { 1,1 });
            //Console.WriteLine(res);

            //10、调用构造函数
            ConstructorInfo ci = type.GetConstructor(new Type[] { });
            object o = ci.Invoke(null);
            Console.ReadKey();
        }
    }

反射相关的补充方法

    internal class Program
    {
        static void Main(string[] args)
        {
            //IsAssignableFrom: 后面的是否可以赋值给前面的
            //特点:既可以判断类,也可以判断接口
            //bool b = typeof(Person).IsAssignableFrom(typeof(Teacher));
            //bool b2 = typeof(I1).IsAssignableFrom(typeof(Teacher));


            //IsInstanceOfType:后面的对象,是否可以赋值给前面的类型
            Person p = new Person();
            Student s = new Student();
            Teacher t = new Teacher();
            //bool b3 = typeof(Person).IsInstanceOfType(p);
            //bool b4 = typeof(Person).IsInstanceOfType(s);
            //bool b5 = typeof(Person).IsInstanceOfType(t);
            //bool b6 = typeof(I2).IsInstanceOfType(t);
            //Console.WriteLine(b3);
            //Console.WriteLine(b4);
            //Console.WriteLine(b5);
            //Console.WriteLine(b6);

            //IsSubclassOf 跟接口没关系
            bool b = t.GetType().IsSubclassOf(typeof(I2));
            //Console.WriteLine(b);

            Console.WriteLine(typeof(Animal).IsAbstract);
            Console.WriteLine(typeof(Person).IsAbstract);
            Console.WriteLine(typeof(I2).IsAbstract);
            Console.ReadKey();
        }
    }

    class Person
    {

    }
    class Student : Person
    { }

    abstract class Animal
    { }

    interface I1
    {

    }

    interface I2 : I1 { }

    class Teacher : I2
    { }

记事本插件开发

1、Form1

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Plug_in_Rule_DLL;
namespace _10_记事本插件开发
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //程序加载的时候,读取指定目录下的插件
            //1、获取插件存储文件夹的路径
            string path = Assembly.GetExecutingAssembly().Location;
            path = Path.GetDirectoryName(path);
            path = Path.Combine(path, "Plug-in-Components");
            //2、读取该路径下所有的插件
            string[] files = Directory.GetFiles(path);

            //3、通过Assembly去加载程序集
            foreach (var file in files)
            {
                //4、获取到当前循环到的插件程序集
                Assembly ass = Assembly.LoadFile(file);
                //5、获取程序集中的元数据
                //types:都是程序集中的数据类型。(类、接口、抽象类、委托、事件、.......)
                Type[] types = ass.GetExportedTypes();
                //6、对types做筛选
                foreach (var type in types)
                {
                    //筛选条件:1、实现了Plug_in_Rule接口的类     2、不能接口或者抽象类
                    if (typeof(Plug_in_Rule).IsAssignableFrom(type) && !type.IsAbstract)
                    {
                        //7、获取类型中的属性和方法
                        //动态的创建插件的对象
                        object o = Activator.CreateInstance(type);
                        Plug_in_Rule pir = (Plug_in_Rule)o;
                        //调用Name属性,赋值给Menustrip
                        ToolStripItem tsi = menuStrip1.Items.Add(pir.Name);
                        //8、给添加的小选项卡设置单击事件
                        tsi.Click += Tsi_Click;
                        //9、把pir接口,从Load方法中,传到Tsi_Click中
                        tsi.Tag = pir;
                    }
                }
            }

            //通过反射,获取程序集中的数据:Name ChangeText()

            //把Name加载到Menustrip菜单中,给菜单注册一个单击事件

            //单击的时候,执行ChangeText
        }

        //单击选项卡的时候,调用ChangeText()
        private void Tsi_Click(object sender, EventArgs e)
        {
            //sender  事件是谁的,sender就是谁
            ToolStripItem tsi = sender as ToolStripItem;

            Plug_in_Rule p = (Plug_in_Rule)tsi.Tag;

            p.ChangeText(textBox1);
        }
    }
}

2、Plug_in_Rule 插件开发的接口规范

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Plug_in_Rule_DLL
{
    /// <summary>
    /// 插件开发的接口规范
    /// </summary>
    public interface Plug_in_Rule
    {
        //接口中的只读属性,不是自动属性
        string Name { get; }
        //让插件开发人员,实现该方法,对文本的样式进行修改
        void ChangeText(TextBox textBox);

    }
}

3、Str_To_Lower 全部转小写功能

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Plug_in_Rule_DLL;
using System.Windows.Forms;
namespace Str_To_Lower_DLL
{
    public class Str_To_Lower : Plug_in_Rule
    {
        public string Name { get { return "全部转小写!!!!!"; } }

        public void ChangeText(System.Windows.Forms.TextBox textBox)
        {
            textBox.Text = textBox.Text.ToLower();
        }
    }
}

4、Str_To_Upper 全部转大写功能

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Plug_in_Rule_DLL;
using System.Windows.Forms;
namespace Str_To_Upper_DLL
{
    /// <summary>
    /// 要拓展插件功能的人
    /// </summary>
    public class Str_To_Upper : Plug_in_Rule
    {
        public string Name { get { return "全部转大写!!!!"; } }

        public void ChangeText(System.Windows.Forms.TextBox textBox)
        {
            textBox.Text = textBox.Text.ToUpper();
        }
    }
}