C#基础系列——委托实现简单设计模式
前言:上一篇介绍了下多线程的相关知识:C#基础系列——多线程的常见用法详解,里面就提到了委托变量。这篇简单介绍下委托的使用。当然啦,园子里面很多介绍委托的文章都会说道:委托和事件的概念就像一道坎,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托和事件就觉得心里发慌。确实这东西就像最开始学C语言的指针一样,令人有一种很纠结的感觉,总觉得要调用一个方法直接调用就行了,为啥非要定义一个委托时执行这个方法呢。其实在C#里面很多的技术都是为了重用和简化代码而生,委托也不例外,很多使用C#多态去实现的设计模式其实都可以使用委托的方式去改写,可以理解为一种轻量级的设计模式吧。博主打算抽一篇专门分享下多态和委托实现设计模式的异同。这篇就先介绍简单委托的使用。
一、什么是委托:C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。用博主的话说,委托就是一种允许将方法名称作为参数传递的引用类型。它定义的是方法的类型,可以说就是方法的抽象,那么反过来说,方法可以理解为委托的实例,如public delegate void TestDelegate(string str);这种委托定义的就是所有参数类型为string,没有返回值的方法的一种抽象。
二、为什么要使用委托:记得博主刚开始做项目的时候看到委托的写法就头大,总觉得这是没事找事,唯一的好处貌似就是代码看上去很酷~~随着工作的累积,发现项目中某些小的需求使用这种轻量级的委托来实现的时候确实能减少很多代码量。
三、委托的使用:
1、.Net Framework 里面的委托类型:使用过委托的朋友可能注意到了C#里面定义了两种类型的委托变量,基本能满足我们的一般需求。
(1)Action类型的委托:C#里面定义Action委托用于抽象化那种没有返回值的方法。将Action变量转到定义可知它的最简单形式:
// 摘要:
// 封装一个方法,该方法不具有参数并且不返回值。
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
public delegate void Action();
它定义是就是一种没有返回值没有参数的委托。同时Action还提供了16个泛型的委托,用于定义方法的传入参数:

我们来看他们的使用方法,我们首先定义测试的方法:
private static void Test5(int a, int b, int c)
{
//......
} //无参数无返回值
private static void Test1()
{
Console.WriteLine("Func Test1, No Parameter");
} //有参数无返回值
private static void Test2(string str)
{
Console.WriteLine("Func Test2, Parameter is" + str);
} //无参数有返回值
private static object Test3()
{
Console.WriteLine("Func Test3, Parameter");
return Guid.NewGuid().ToString();
} //有参数有返回值
private static object Test4(string strRes)
{
Console.WriteLine("Func Test4, Parameter and Return Value");
return strRes;
}
调用:
static void Main(string[] args)
{
//1.无参无返回值方法
var oAction1 = new Action(Test1);
oAction1.Invoke();//调用方式一
oAction1();//调用方式二 //2.有参无返回值
var oAction2 = new Action<int, int, int>(Test5);
oAction2.Invoke(, , );
oAction2(, , );
//匿名方法的调用
var oAction3 = new Action<int, int, int>((a,b,c) => {
//......
});
oAction3.Invoke(, , );
}
(2)Func类型的委托:还记得Linq里面的扩展方法Where()、Select()等方法的参数吗。public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)。这里的参数就是一个Func类型的委托。C#里面Func类型的委托用于处理有参数有返回值的方法。不多说,上代码:
static void Main(string[] args)
{
var oFunc1 = new Func<object>(Test3);
var ofuncRes1 = oFunc1.Invoke();
var oFunc2 = new Func<string, object>(Test4);
oFunc2("a");
}
知道了Func的方法就可以推想到我们神奇的lamada表达式了,其实lamada表达式就是一个匿名的委托。
var lstTest = new List<string>();
var lstRes = lstTest.Where(x => x.Contains("_"));
这个Where里面的lamada表达式我们把他拆解:
private static bool TestWhere(string x)
{
return x.Contains("_");
}
var oFunc = new Func<string, bool>(TestWhere);
lstRes = lstTest.Where(oFunc);
是不是一样一样的~~
2、自定义委托:
public delegate void TestDelegate(string str);
其实很多人应该都自己写过Action、Func类型的委托。其实自己定义一个泛型委托也很简单:
public delegate void MyAction<in T>();
public delegate TResult MyFunc<in T, out TResult>(T arg);
其实使用起来和系统的Action和Func基本没有区别。
3、委托的合并和拆解就放在事件里面分享了。这篇且过之。。。
4、如果按照上面的方法去使用委托,那真的是要别扭死人了,因为调用方法直接用方法名调用就好了,何必还要定义一个委托变量去调用,这不是将简单问题复杂化么。确实,上面只是为了介绍委托而写的代码,实际项目中肯定不会这么用。其实委托在项目中一般用在将委托变量作为参数传递或者函数回调。来看下面代码:
class Program
{
static void Main(string[] args)
{ Person strHelper = new Person();
string r1 = strHelper.ProcessFunc("中国人", "你好", new MyDelegate(strHelper.ChineseSayHello));
string r2 = strHelper.ProcessFunc("English", "Hello", new MyDelegate(strHelper.EnglishSayHello));
string r3 = strHelper.ProcessFunc("Japanese", "こんにちは", new MyDelegate(strHelper.JapaneseSayHello)); Console.WriteLine(r1);
Console.WriteLine(r2);
Console.WriteLine(r3); Console.ReadKey();
} } public delegate string MyDelegate(string s1, string s2);
public class Person
{
public string ProcessFunc(string s1, string s2, MyDelegate process)
{
return process(s1, s2);
} public string ChineseSayHello(string s1, string s2)
{
return s1 +","+ s2;
} public string EnglishSayHello(string s1, string s2)
{
return s1 + "," + s2;
} public string JapaneseSayHello(string s1, string s2)
{
return s1 +","+ s2;
}
}
得到结果:

public string ProcessFunc(string s1, string s2, MyDelegate process)里面定义了一个回调函数,可以将任意一个符合这个委托的方法传递进去,得到想对应的结果。细看这种设计是不是和工厂设计模式十分相似,我简单构造了个工厂:
public class Person
{
public virtual string SayHello(string s2)
{
return s2;
}
}
public class Chinese : Person
{
public override string SayHello(string s2)
{
return "中国人," + s2;
}
} public class English : Person
{
public override string SayHello(string s2)
{
return "English," + s2;
}
} public class Japanese : Person
{
public override string SayHello(string s2)
{
return "Japanese," + s2;
}
} //Main函数里面调用
class Program
{
static void Main(string[] args)
{
var r1 = GetPerson("你好").SayHello("你好");
var r2 = GetPerson("Hello").SayHello("Hello");
var r3 = GetPerson("こんにちは").SayHello("こんにちは");
Console.WriteLine(r1);
Console.WriteLine(r2);
Console.WriteLine(r3); Console.ReadKey();
} public static Person GetPerson(string strType)
{
if (strType == "你好")
return new Chinese();
else if (strType == "Hello")
return new English();
else
return new Japanese();
} }
得到结果和上面相同:

这样一比较是不是对委托的用法有点感觉了呢~~如果你不怕麻烦,可以在项目是用起来试试,相信你会有收获~~
C#基础系列——委托实现简单设计模式的更多相关文章
- C#基础系列——委托和设计模式(二)
前言:前篇 C#基础系列——委托实现简单设计模式 简单介绍了下委托的定义及简单用法.这篇打算从设计模式的角度去解析下委托的使用.我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性 ...
- C#基础系列——异步编程初探:async和await
前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了 ...
- C#基础系列——一场风花雪月的邂逅:接口和抽象类
前言:最近一个认识的朋友准备转行做编程,看他自己边看视频边学习,挺有干劲的.那天他问我接口和抽象类这两个东西,他说,既然它们如此相像, 我用抽象类就能解决的问题,又整个接口出来干嘛,这不是误导初学者吗 ...
- c#基础系列(转)
转:http://www.cnblogs.com/landeanfen/p/4953025.html C#基础系列——一场风花雪月的邂逅:接口和抽象类 前言:最近一个认识的朋友准备转行做编程,看他自己 ...
- C#基础系列——再也不用担心面试官问我“事件”了
前言:作为.Net攻城狮,你面试过程中是否遇到过这样的问题呢:什么是事件?事件和委托的区别?既然事件作为一种特殊的委托,那么它的优势如何体现?诸如此类...你是否也曾经被问到过?你又是否都答出来了呢? ...
- C#基础篇——委托
前言 在本章中,主要是借机这个C#基础篇的系列整理过去的学习笔记.归纳总结并更加理解透彻. 在.Net开发中,我们经常会遇到并使用过委托,如果能灵活的掌握并加以使用会使你在编程中游刃有余,然后对于很多 ...
- [.net 面向对象编程基础] (21) 委托
[.net 面向对象编程基础] (20) 委托 上节在讲到LINQ的匿名方法中说到了委托,不过比较简单,没了解清楚没关系,这节中会详细说明委托. 1. 什么是委托? 学习委托,我想说,学会了就感觉简 ...
- C#基础系列:实现自己的ORM(反射以及Attribute在ORM中的应用)
反射以及Attribute在ORM中的应用 一. 反射什么是反射?简单点吧,反射就是在运行时动态获取对象信息的方法,比如运行时知道对象有哪些属性,方法,委托等等等等.反射有什么用呢?反射不但让你在运行 ...
- 你所不知道的ASP.NET Core MVC/WebApi基础系列(一)
前言 最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时间也是一直在看ASP.NET Core的内容,所以后续会穿插讲EF Core和ASP.NET Core,别认为你会 ...
随机推荐
- Java泛型介绍——HashMap总结
今天在编程中,需要使用到Hashmap来存储和传递数据,发现自己学习Java这么久,实际上对泛型依旧知之甚少,搜索整理了一下HashMap的使用. HashMap的声明初始化,因为泛型的原因,起两个参 ...
- iOS开发-UI 从入门到精通(四)
一.UITextField 1.UITextField是什么? (1)UITextField(输入框):是控制文本输入和显示的控件.在App中UITextField出现频率也比较高: (2)iOS系统 ...
- Linux系统安装NoSQL(MongoDB和Redis)步骤及问题解决办法
➠更多技术干货请戳:听云博客 如下是我工作中的记录,介绍的是linux系统下NoSQL:MongoDB和Redis的安装过程和遇到的问题以及解决办法: 需要的朋友可以按照如下步骤进行安装,可以快速安装 ...
- JNI笔记1
一.什么是JNI Java Native Interface(JNI)是Java语言的本地编程接口 是 Java 与操作系统本地代码互相调用的功能的接口 二.Java 调用C/C++步骤: 1.在Ja ...
- iOS 实用博客整理(连载版)
iOS 实用博客整理(连载版) 本博客为本人觉得不错的博客的暂存地,并不是本人所写. 1.iOS开发 如何适配iOS10? 2.UIWebView和WKWebView的比较和选择 3. 如何快速的开发 ...
- iOS 实现转盘的效果
效果 #import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBO ...
- iOS开发之Socket通信实战--Request请求数据包编码模块
实际上在iOS很多应用开发中,大部分用的网络通信都是http/https协议,除非有特殊的需求会用到Socket网络协议进行网络数 据传输,这时候在iOS客户端就需要很好的第三方CocoaAsyncS ...
- PHP开发之Zend Studio快捷键汇总
应用场景 快捷键 功能 查看快捷键 ctrl+shift+l 显示所有快捷键列表 查看和修改快捷键 打开Window->Preferences->General->keys 修改字体 ...
- curl操作CouchDB
couchdb 服务器地址: 127.0.0.1 端口:5984 添加数据库 连接到couchdb curl -X GET http://127.0.0.1:5984 {"couchdb&q ...
- Provider:SSL Provider,error:0-等待的操作过时
今天一同事使用SSMS 2012 连接数据库时,遇到了"provider:SSL Provider,error:0-等待的操作过时",搜索了一下,遇到一哥 们也遇到这个问题:SQL ...