单例模式
假如我们想在第一个窗体中,再打开一个窗体,我们可以添加一个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就拿到了委托类型的方法。