前言:上一篇介绍了下多线程的相关知识: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#基础系列——委托实现简单设计模式的更多相关文章

  1. C#基础系列——委托和设计模式(二)

    前言:前篇 C#基础系列——委托实现简单设计模式 简单介绍了下委托的定义及简单用法.这篇打算从设计模式的角度去解析下委托的使用.我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性 ...

  2. C#基础系列——异步编程初探:async和await

    前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了 ...

  3. C#基础系列——一场风花雪月的邂逅:接口和抽象类

    前言:最近一个认识的朋友准备转行做编程,看他自己边看视频边学习,挺有干劲的.那天他问我接口和抽象类这两个东西,他说,既然它们如此相像, 我用抽象类就能解决的问题,又整个接口出来干嘛,这不是误导初学者吗 ...

  4. c#基础系列(转)

    转:http://www.cnblogs.com/landeanfen/p/4953025.html C#基础系列——一场风花雪月的邂逅:接口和抽象类 前言:最近一个认识的朋友准备转行做编程,看他自己 ...

  5. C#基础系列——再也不用担心面试官问我“事件”了

    前言:作为.Net攻城狮,你面试过程中是否遇到过这样的问题呢:什么是事件?事件和委托的区别?既然事件作为一种特殊的委托,那么它的优势如何体现?诸如此类...你是否也曾经被问到过?你又是否都答出来了呢? ...

  6. C#基础篇——委托

    前言 在本章中,主要是借机这个C#基础篇的系列整理过去的学习笔记.归纳总结并更加理解透彻. 在.Net开发中,我们经常会遇到并使用过委托,如果能灵活的掌握并加以使用会使你在编程中游刃有余,然后对于很多 ...

  7. [.net 面向对象编程基础] (21) 委托

    [.net 面向对象编程基础] (20)  委托 上节在讲到LINQ的匿名方法中说到了委托,不过比较简单,没了解清楚没关系,这节中会详细说明委托. 1. 什么是委托? 学习委托,我想说,学会了就感觉简 ...

  8. C#基础系列:实现自己的ORM(反射以及Attribute在ORM中的应用)

    反射以及Attribute在ORM中的应用 一. 反射什么是反射?简单点吧,反射就是在运行时动态获取对象信息的方法,比如运行时知道对象有哪些属性,方法,委托等等等等.反射有什么用呢?反射不但让你在运行 ...

  9. 你所不知道的ASP.NET Core MVC/WebApi基础系列(一)

    前言 最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时间也是一直在看ASP.NET Core的内容,所以后续会穿插讲EF Core和ASP.NET Core,别认为你会 ...

随机推荐

  1. Oracle常用SQL查询

    一.ORACLE的启动和关闭 1.在单机环境下要想启动或关闭oracle系统必须首先切换到oracle用户,如下: su - oracle a.启动Oracle系统 oracle>svrmgrl ...

  2. chrome 调试 SASS

    第一步: 执行sass预编译命令 先来我的项目文件夹结构: ->进入sass /css文件下->打开cmd命令 ->输入sass --watch --scss  test.scss: ...

  3. iOS BUG: Unbalanced calls to begin/end appearance transitions for <XXXViewController: 0x7fcea3730650>.

    自定义TabBarController Push下一级Controller时 会报这样的错误:Unbalanced calls to begin/end appearance transitions ...

  4. iOS GCD的 一次性执行、定时器、迭代、队列组

  5. 服务器重启后导致访问ArcServer地图服务须登录

    问题状况: 重启服务器后,在访问网站的地图服务时会提示登录,输入各种密码账号都不好用 解决方法: 通过进入[服务管理器],找到ArcGISServer的服务,重新启动该服务就可以.

  6. nodejs的child_process同步异步

    nodejs是一种单线程模型,但是,使用nodejs的child_process模块可以实现多进程任务.利用child_process可以创建子进程,实现子进程和主进程之间的通信. nodejs v0 ...

  7. initialize和init以及load方法的区别与使用以及什么时候调用

    initialize不是init initialize在这个类第一次被调用的时候比如[[class alloc]init]会调用一次initialize方法,不管创建多少次这个类,都只会调用一次这个方 ...

  8. android 7.0 学习笔记(一)

    导读 增强的Doze模式 后台优化 Data Saver 一.增强的Doze模式 Android N对Android M引进的Doze模式进行了进一步的增强,变化体现在两个方面.一方面是降低了进入Do ...

  9. SQL Server中的“最大并行度”的配置建议

    SQL Server中的最大并行度(max degree of parallelism)如何设置呢? 设置max degree of parallelism有什么好的建议和指导方针呢?在微软官方文档R ...

  10. ansible 初探nginx安装

    我的配置: /etc/hosts: /etc/ansible/hosts: nglinx安装包: ansible自动化安装nginx: 1.安装ansible. 2.创建目录结构: mkdir -p ...