C# 中 用委托有啥好处? 它起啥作用?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 中 用委托有啥好处? 它起啥作用?相关的知识,希望对你有一定的参考价值。

什么是委托
  首先要知道什么是委托,用最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。

如何使用委托
  在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。

声明,如:

1 namespace Vczx.ProCSharp.Exc
2
3 delegate double MathsOp( double x );
4 //class defination here
5

  这就声明了一个委托,意义:任何一个返回值为double,且只有一个形参为double的函数,都可以用这个委托来调用。
  注意:委托的声明位置在namespace里面,类的外面。其实,委托的声明也可以在类的里面,甚至是任何一个可以声明类的地方。
  实例化:
  首先我们要先有一个满足委托声明的方法,假设一个返回一个数的2倍的方法:

1class MathsOperations
2
3 public static double MultiplyBy2( double value )
4
5 return value * 2;
6
7

  有了这样一个方法,我们就可以实例化一个委托了:
MathsOp operation = new MathsOp( MathsOperations.MultiplyBy2 );
  在实例化一个委托时,要给它一个参数,这个参数就是委托执行的方法,它可以是静态方法,也可以是实例方法(这一点有别于函数指针,函数指针只能调用静态方法),如:
MathsOp operation = new MathsOp( new Class1().Method1 );

在实例化完一个委托之后,就可以用这个委托来调用方法了:
double result = operation( 1.23 );

例子代码:

1namespace Vczx.ProCSharp.Exc
2
3 delegate double MathsOp( double x );
4 class Start
5
6 public class MyDelegate
7
8 public static double MultiplyBy2( double x )
9
10 return x * 2;
11
12
13 [STAThread]
14 static void Main(string[] args)
15
16 MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 );
17 double x = 1.23;
18 double result = operation( x );
19 Console.WriteLine( "0 multiply by 2 is 1", x, result );
20 Console.Read();
21
22
23

多路广播委托
   前面使用的委托只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显示调用这个委托。其实委托也可以包含多个方法,这种委托就是多路广播委托。多路广播委托派生于System.MulticastDelegate,它的Combine方法允许把多个方法调用链接在一起,我们可以通过+=来向委托添加调用方法,也可以用-=删除其中的调用方法。如:

1namespace Vczx.ProCSharp.Exc
2
3 public class MyDelegate
4
5 public static void MultiplyBy2( double value )
6
7 double result = value * 2;
8 Console.WriteLine( "Multiplying by 2: 0 gives 1", value, result );
9
10
11 public static void Squre( double value )
12
13 double result = value * value;
14 Console.WriteLine( "Squaring: 0 gives 1", value, result );
15
16
17
18 delegate void MathsOp( double x );
19
20 class Start
21
22 [STAThread]
23 static void Main(string[] args)
24
25 MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 );
26 operation += new MathsOp( MyDelegate.Squre );
27 double x = 1.23;
28 operation( x );
29
30 operation -= new MathsOp( MyDelegate.MultiplyBy2 );
31 operation( x );
32
33 Console.Read();
34
35
36

输出:
Multiplying by 2: 1.23 gives 2.46
Squaring: 1.23 gives 1.5129
Squaring: 1.23 gives 1.5129

  注意,多路广播委托声明时必须返回void,否则返回值不知道应该送回什么地方。对此,我做了一个测试:如果不将委托的声明返回void,则返回值返回的是最后一个链入委托链的方法的返回值,编译不会出错。

为什么要用委托
  使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。
参考技术A 委托的好处很多,你可以先看设计模式里的观察者模式,在没有委托这个模式的还是存在观察者和被观察者之间的耦合,而委托可以是两者更大的解除耦合。在面向对象编程能接触耦合就是最大的好处,委托也可以说是观察者模式,这个模式的好处也可以说是委托的好处,它能使一个对象状态的改变立即通知其他对象,而这个对象和其它的对象是完全分离的,就是互相不知道对方的存在,这样在程序规模变大的情况下更加容易维护(每一个对象的修改不涉及另一个对象),更加容易扩展(理由同上),也更加灵活。一句话就是达到解耦的目的。 参考技术B C# 委托实际上类似于C++中的函数指针,因为C#中不存在指针,所以用委托可以完成一些原来在C++中用函数指针完成的操作,例如传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。但与函数指针相比,委托有许多函数指针不具备的优点。
1、函数指针只能指向静态函数,而委托既可以引用静态函数,又可以引用非静态成员函数。在引用非静态成员函数时,委托不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。
2、与函数指针相比,委托是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法,无须担心delegate会指向无效地址或者越界地址。

实现一个委托是很简单的,通过以下3个步骤即可实现一个delegate:
1.声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。
声明一个代理的例子:
public delegate int MyDelegate(string message);

2.创建delegate对象,并将你想要传递的函数作为参数传入。
创建代理对象的方法:
1). MyDelegate myDelegate = new MyDelegate(实例名.方法名);
2). MyDelegate myDelegate = new MyDelegate(类名.方法名);
注:如果需要代理的方法是一个static静态方法的话,采用第2种方式,否则采用第1种方式。

3.在要实现异步调用的地方,通过上一步创建的对象来调用方法。
可以直接使用代理调用代理所指向的方法:
myDelegate(向方法传递的参数);

下面是一些需要注意的事情:
“代理”(delegate)(代表、委托):“委托”是类型安全的并且完全面向对象的。
(1)在C#中,所有的委托都是从System.Delegate类派生的(delegate是System.Delegate的别名)。
(2)委托隐含具有sealed属性,即不能用来派生新的类型。
(3)委托最大的作用就是为类的事件绑定事件处理程序。
(4)在通过委托调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。
(5)在委托实例中可以封装静态的方法也可以封装实例方法。
(6)在创建委托实例时,需要传递将要映射的方法或其他委托实例以指明委托将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。
(7)只有当两个委托实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。
(8)多个委托实例可以形成一个委托链,System.Delegate中定义了用来维护委托链的静态方法Combion,Remove,分别向委托链中添加委托实例和删除委托实例。
(9)委托三步曲:
a.生成自定义委托类:delegate int MyDelegate();
b.然后实例化委托类:MyDelegate d = new MyDelegate(MyClass.MyMethod);
c.最后通过实例对象调用方法:int ret = d();
参考技术C 就是找别人帮你做事

使用自动映射器有啥好处?

【中文标题】使用自动映射器有啥好处?【英文标题】:What are the advantages of using automapper?使用自动映射器有什么好处? 【发布时间】:2011-04-29 02:44:49 【问题描述】:

我必须在 C# 项目中使用的域类和发送到 Flash 客户端的类之间进行一些对象到对象的映射。

我的第一选择是 Automapper。但是我遇到了一些问题(嵌套属性,没有定义无参数构造函数)。事实证明,用 Automapper 映射一个非常复杂的类型并不是那么容易。

为什么不实现如下方法?

  ClassA GetClassAByClassB(ClassB pObj)

     
     ClassA objA = new ClassA();  
     objA.Prop1 = pObj.Prop1;  
     objA.NestedType.Prop2 = pObj.Prop2;  
     //....Some more.....  
     return objA;  
     

它与使用 Automapper 完成映射具有完全相同的灵活性。您仍然必须提供将源对象中的哪个属性复制到目标对象中的哪个属性中。您只需使用 = 而不是 lambda 表达式即可。

但是,如果您更改域类中的某些内容,则无论如何都必须更改此“映射”部分。那么,与文字映射相比,使用 Automapper 的主要优势是什么?

【问题讨论】:

【参考方案1】:

AutoMapper 声称的一个好处是按约定映射。这是"AutoMapper Introduction and Samples"的引述

AutoMapper 的魅力就在于此。当您的课程对齐时 按照惯例,您的映射配置可以是 简单

这是有代价的。重命名或更改目标或源属性名称将破坏映射并引入运行时错误。

如果不使用按惯例映射,AutoMapper 将失去优势。在这种情况下,我宁愿写一个像这样的工厂函数。

public static ClassA MapToClassA(this ClassB b)

    return new ClassA()
    
        propA = b.propA;
        propB = b.propB;
        propC = b.propC;
    

然后你会像这样构造目标对象

var classA = classB.MapToClassA();

而不是

var classA = Mapper.Map<ClassB, ClassA>(classB)

就我个人而言,我更喜欢工厂函数,因为它的明确性、可读性和调试友好性。祝你好运,在第二种情况下,ClassB 是如何映射到 ClassA 的,是否加载了映射配置文件,或者为什么在调用 Map&lt;&gt;() 函数时出现异常,或者为什么某些属性被分配了错误的值。

【讨论】:

【参考方案2】:

因为使用 AutoMapper,您不必实现这些方法 ;-)

你的方法需要写很多

classA.propA = classB.propA;
classA.propB = classB.propB;
classA.propC = classB.propC;
classA.propD = classB.propD;
classA.propE = classB.propE;

AutoMapper 使用约定来计算它自己。更重要的是,您不必担心pObj == null(在这种情况下,您的代码将抛出NulLReferenceException)。

您还可以在地图中定义转换(即字符串到日期时间)。

Mapper.CreateMap<User, UserModel>().ForMember(d => d.LastLogin, c => c.MapFrom<DateTime?>(u => u.Credential.LastLogin));

AutoMapper 也支持嵌套属性。

在此处阅读更多信息:AutoMapper Introduction and Samples

【讨论】:

不具有相同名称的属性怎么办?和嵌套属性?我想我应该改变约定,但有时一侧的属性是“PositionX”,而另一侧只是“X”。 (只是一个例子 - 属性 anmes 可能非常不可预测)。所以我不应该在我的情况下使用 Automapper 吗? @Katalonis - 然后使用 lambda 以类型安全的方式配置映射器。添加了代码示例和链接。 当然,另一方面是,如果您看到的 dest.MyProp, opt =&gt; opt.Ignore()dest.MyProp, opt =&gt; opt.MapFrom(src =&gt; Transformation(src.MyProp)) 比通过自动映射获得的更多,那就没那么好了。或者,就像 ank2k11 points out 一样,当 map-by-magic-string-convention 遇到问题时要小心。 Xiaoguo hits nail on its head:“当你的类按照惯例对齐时,你的映射配置可以很简单”。否则,您实际上正在实现这些方法,只需使用 AutoMapper。【参考方案3】:

有时使用映射器,很难追踪错误。例如,如果我们在数据类中拼错了 Employee 而在视图模型类中拼错了 Emplyee,那么像小映射器这样的映射器不会抛出任何异常,除非我们明确地将映射器设置为严格映射,并且在此期间代码编译和运行完美,但我们是无法追踪错误。这种情况很少发生在手动映射中,因此手动映射对象比自动映射有一些优势。

【讨论】:

我正在尝试调试为什么 automapper 没有应用转换。

以上是关于C# 中 用委托有啥好处? 它起啥作用?的主要内容,如果未能解决你的问题,请参考以下文章

装系统中的后门是啥?起啥作用?有啥有利和有害的?如何弄?

plc的电源模块起啥作用,

C#和Java中的构造器constructor是啥?起啥作用?为啥不可以被override??

C#继承有啥作用

网页文件必须含JS,CSS吗,起啥用途?

STM32中DMA有啥好处