C#入门学习——单例模式和委托

单例模式

假如我们想在第一个窗体中,再打开一个窗体,我们可以添加一个bottom按钮,写一个事件,当我们点击按钮的时候,创建并显示窗体2。

不过如果这样写,我们可以一直创建出窗体,但我们只想要一个。这时候我们使用单例模式的思路。

1.构造函数私有化

        private Form2()
        {
            InitializeComponent();
        }

2.提供一个静态方法,返回一个对象

        public static Form2 GetSingle()
        {
            if (FrmSingle == null)
            {
                FrmSingle = new Form2();
            }
            return FrmSingle;
        }

3.创建一个单例

我们创建一个静态的字段来存储对象,如果我们创建完一次对象后,字段会存进去一个对象,这样就完成了单例的创建

public static Form2 FrmSingle = null;

这个时候,我们在窗体1中创建窗体2的对象如下

            Form2 frm2 = Form2.GetSingle();
            frm2.Show();

委托

为什么要使用委托?

假如现在有三个需求:

1.将一个字符串数组中每个元素都转换成大写
2.将一个字符串数组中每个元素都转换成小写
3.讲一个字符串数组中每个元素两边都加上双引号

可以看出,这三个需求不同的地方就是方法体这部分。那么就想了,有没有这么一种可能,单独传进来一个东西,具体大写小写还是双引号取决于传进来的是什么。是不是可以传一个方法呢?

这个时候可以把方法当做参数传进来,那么这个参数的类型就是委托类型。

语法

首先,声明一个委托指向一个函数

public delegate void DelSayHi(string name);

使用delegate关键字,委托所指向的函数,必须跟委托具有相同的签名(参数和返回值)

        public static void Test(string name,DelSayHi del)
        {
            del(name);
        }
        public static void Say(string name)
        {
            Console.WriteLine("吃了吗" + name);
        }
        public static void Say2(string name)
        {
            Console.WriteLine("nice to meet you"+name);
        }

然后,我们来调用这个方法

        DelSayHi del = new DelSayHi(Say);
        del("zs");

上面就是委托的一个基本的语法了。

不过这样做貌似意义并不大,又是创建对象什么的,如果我们想实现Say方法,直接调用就可以了。

            DelSayHi del = Say2;
            del("zs");

我们可以把方法直接赋值给委托类型。(虽然没有new但其实依然new了一个对象)

现在,我们可以直接调用这个Test()方法了。

            Test("张三", Say);
            Console.ReadKey();

多播委托

委托可以指向多个方法。

    public delegate void DelTest();
    class Program
    {
        static void Main(string[] args)
        {
            DelTest del = T1;
            del += T2;
            del += T3;
            del += T4;
            del -= T3;
            del();
            Console.ReadKey();
        }
        public static void T1()
        {
            Console.WriteLine("woshiT1");
        }
        public static void T2()
        {
            Console.WriteLine("woshiT2");
        }
        public static void T3()
        {
            Console.WriteLine("woshiT3");
        }
        public static void T4()
        {
            Console.WriteLine("woshiT4");
        }

    }

匿名函数

匿名函数就是没有方法名的方法

如果一个方法只需要执行1次,那么我们可以将这个方法写成匿名委托。

public delegate void DelSayHi(string name);
            DelSayHi del = delegate(string name) 
            {
                Console.WriteLine("你好" + name);
            };

lamda表达式

        public delegate void DelOne();
        public delegate void DelTwo(string name);
        public delegate string DelThree(string name);
            DelOne del = () => { };
            DelTwo del2 = (string name) => { };
            DelThree del3 = (string name) => { return name; };

不管是匿名函数还是lamda表达式,委托所指向的函数,必须跟委托具有相同的签名(参数和返回值)。

求数组(未知类型)最大值

        public static int GetMax(int[] nums)
        {
            int max = nums[0];
            for (int i = 0; i < nums.Length; i++)
            {
                if (max < nums[i])
                {
                    max = nums[i];
                }
            }
            return max;
        }
        public static string GetMax(string[] names)
        {
            string max = names[0];
            for (int i = 0; i < names.Length; i++)
            {
                if (max.Length < names[i].Length)
                {
                    max = names[i];
                }
            }
            return max;
        }

我们之前都是在判断int[]的最大值,如果是string[]呢?

如果这么去写,两个方法的参数和返回值类型都不一样,委托不好去声明,依然会很麻烦。

那么我们应该用object类型,因为object是所有类的父类。

public delegate int DelCompare(object o1,object o2);
        public static object GetMax(object[] nums,DelCompare del)
        {
            object max = nums[0];
            for (int i = 0; i < nums.Length; i++)
            {
                //要传一个比较的方法
                if (del(max,nums[i])<0)
                {
                    max = nums[i];
                }
            }
            return max;
        }
            object result = GetMax(o, (object o1, object o2) =>
            {
                string s1 = (string)o1;
                string s2 = (string)o2;
                return s1.Length - s2.Length;
            });
            Console.WriteLine(result);
            Console.ReadKey();

现在我们只需要修改方法体这一部分,就可以了。

那么还有没有更洋气的写法呢?

下面就来说明泛型委托

泛型委托

我们将上题,所有的object类型换成泛型T

public delegate int DelCompare<T>(T t1, T t2);
        public static T GetMax<T>(T[] nums, DelCompare<T> del)
        {
            T max = nums[0];
            for (int i = 0; i < nums.Length; i++)
            {
                //要传一个比较的方法
                if (del(max, nums[i]) < 0)
                {
                    max = nums[i];
                }
            }
            return max;
        }
            int[] nums = { 1, 2, 3, 4, 5 };
            int max = GetMax<int>(nums,Compare1);

当我们调用委托方法的时候,<>中的类型是什么,参数和返回值的类型就会是什么,这比刚才的写法更加省事了。

然后我们只需要去写一个相同返回值参数的方法传进去即可。

        public static int Compare1(int n1,int n2)
        {
            return n1 - n2;
        }

使用委托实现窗体传值

Form1

Form2

 

 现在我希望,按1的按钮,窗体2被创建,在2中按按钮,将文本框中内容传给1。

创建事件,点击1中按钮,生成窗体2

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 frm2 = new Form2();
            frm2.Show();
        }

再写一个方法,改变label文本

        void ShowMsg(string str)
        {
            label1.Text = str;
        }

现在1只有方法,但是却没有参数,2只有参数,却没有方法。

我们可以在创建窗体2对象的时候,通过构造函数,把方法传给窗体2。

Form2 frm2 = new Form2(ShowMsg);
        public DelTest _del;
        public Form2(DelTest del)
        {
            this._del = del;
            InitializeComponent();
        }

在2中声明一个委托

public delegate void DelTest(string str);
        private void button1_Click(object sender, EventArgs e)
        {
            _del(textBox1.Text);
        }

这样2就拿到了委托类型的方法。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值