- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C#中的委托数据类型简介由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
什么是委托?
委托是一个类型安全的对象,它指向程序中另一个以后会被调用的方法(或多个方法)。通俗的说,委托是一个可以引用方法的对象,当创建一个委托,也就创建一个引用方法的对象,进而就可以调用那个方法,即委托可以调用它所指的方法.
来看下面的例子,类deleMthod定义了3个方法,add、minus和multi,他们都具有相同的输入参数列表(int x,int y)和输出参数类型int,那么我们就说这三个方法具有相同的方法签名。开发者可以抽象地用 int 某名称(int x,int y) 的一种类型对方法进行封装,在c#中这种抽象的数据类型叫委托,针对上述的几个方法我们可以定义委托 : public delegate int Handler(int x ,int y),public 是一个访问修饰符,delegate关键字表示这是一个委托,int Hander(int x,int y)表示这个委托的名称.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
deleMethod
{
public
int
add(
int
x,
int
y)
{
return
x + y;
}
public
int
minus(
int
x,
int
y)
{
return
x - y;
}
public
int
multi(
int
x,
int
y)
{
return
x * y;
}
}
|
怎么使用委托 。
使用委托大体有四个步骤:
•定义一个委托,上节已经提及.
•定义委托方法,上节deleMethod类中add、minus、multi都是委托方法,定义的目的就是为了使用它,讲专业点就是为了方法的调用 。
•委托变量及赋值,和类型一样,在使用前需要对变量赋值.
•委托变量的使用.
怎样定义委托变量,还是接着上面的例子。我们已经定义了一个委托类型 public delegate int Handler(int x,int y),和c#语法规范一样定义一个变量并赋值语法是:“类型名 变量名 = new 类型名(方法);”,如上例 。
“Handler deleCall = new Handler(方法名);“,在.net2.0后对于委托的实例化可以简化为” Handler deleCall = 方法名;“.
委托变量的使用,也就是对委托方法的调用。其语法是”int result1 = deleCall(10,20);“或者使用委托调用方法 Invoke,“int result2 = deleCall.Invoke(10,20);”.
具体如何使用可以看看下面的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
Program
{
public
delegate
int
Handler(
int
x,
int
y);
//---定义委托的类型,可以将委托看成一种特殊的数据类型
static
void
Main(
string
[] args)
{
deleMethod dm =
new
deleMethod();
//---实例化包含委托方法的类型
Handler deleCall =
new
Handler(dm.add);
//---定义委托变量delCall,并出示化赋值
int
result1 = deleCall(10, 20);
//---实例方法的调用invoke
Console.WriteLine(
"the add resutl is:{0}"
, result1);
deleCall = dm.minus;
int
result2 = deleCall.Invoke(12, 6);
Console.WriteLine(
"the minus result is:{0}"
, result2);
Console.ReadLine();
}
}
|
如上例所示,定义一个简单的加、减功能如此的复杂,搅来搅去让人头,真是无语,难怪很多朋友谈委托色变晕。在实际使用的过程中,c#还是有很多方式帮我们简化代码.
简化委托 。
预定义的泛型委托 。
c#系统最常见的预定义的委托类型有三种,Func<>委托、Action<>委托、Predicate<>委托,Func<>委托是一个有返回值的委托,输入参数可以多达16个;而Action<>委托是一个没有返回值的委托,它的输入参数也可以多达16个;而Predicate<>是一个具有bool返回类型的委托,它只运行一个输入参数。对于有上例的委托类型,我们可以使用预定义的委托类型Fun<int,int,int>来代替,省去我们自己定义一个什么鬼东西 public delegate int Handler(int x,int y)类型,其代码其实可以简化为如下例所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
namespace DelegateDemo1
{
class
Program
{
static
void
Main(string[] args)
{
deleMethod dm =
new
deleMethod();
Func<
int
,
int
,
int
> fun = dm.add;
//---使用预定义的委托类型Func<>
int
result4 = fun(
8
,
10
);
Func<
int
,
int
,
int
> fun1 = dm.minus;
int
result5 = fun1(
12
,
8
);
Console.WriteLine(
"预定义的委托输出{0},{1}"
, result4, result5);
Console.ReadLine();
}
}
class
deleMethod
{
public
int
add(
int
x,
int
y)
{
return
x + y;
}
public
int
minus(
int
x,
int
y)
{
return
x - y;
}
public
int
multi(
int
x,
int
y)
{
return
x * y;
}
}
}
|
我把委托的方法定义和委托的调用放在一起看,是不是比原先自己定义的一个委托类型简单方便一些?但是这样使用委托还是不怎么清爽,估计在实际应用中很少人会怎么写代码,太不方便了.
匿名委托 。
当委托实例的调用和委托方法的定义分开处理,码农们在读程序代码的时候需要来回的去找委托方法去匹配委托变量,看看参数列表和返回值是否正确,这样的程序代码的可读性很差。其实c#还是有方法让我们简化代码:那就是匿名委托,将方法体直接在委托的实例化时给出,之所以叫匿名委托就是再定义委托的时候省略掉委托的名称,它的定义语法是delegate(参数1,参数2) 后面直接就给出方法体,用大括号将方法体括起。刚看起来比较怪异,接触多了也就习惯了,莫有办法只能去适应c#的语法规范。话说多了是水,还不如看代码来得直接.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
namespace
DelegateDemo1
{
class
Program
{
static
void
Main(
string
[] args)
{
Func<
int
,
int
,
int
> fun =
delegate
(
int
x,
int
y) {
return
x + y; };
Func<
int
,
int
,
int
> fun1 =
delegate
(
int
x,
int
y) {
return
x - y; };
int
result4 = fun(8, 10);
int
result5 = fun1(12, 8);
Console.WriteLine(
"预定义的委托输出{0},{1}"
, result4, result5);
Console.ReadLine();
}
}
}
|
看看是不是在原来的基础上大幅度减少了代码量,肿么办,是否代码量已经减少到极致了?
lambda表达式 。
其实对于委托的定义还可以进一步简化,那就是使用lambda表达式,lambda表达式的定义是(参数列表)=>{方法体},=>读作goes to。lambda表达式对参数列表和方法表达式的精简达到极致,对于上面的例子,用λ表达式可以省略掉匿名委托的关键字和参数类型,系统可以进行类型推断,不影响运行,其简化的代码如下。对.net 1.0,2.0最传统的委托定义和使用,是一个巨大的简化,它剔除了所有多余的语句达到极致.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
namespace
DelegateDemo1
{
class
Program
{
static
void
Main(
string
[] args)
{
Func<
int
,
int
,
int
> fun = (x, y) => x + y;
Func<
int
,
int
,
int
> fun1 = (x, y) => x - y;
int
result4 = fun(8, 10);
int
result5 = fun1(12, 8);
Console.WriteLine(
"预定义的委托输出{0},{1}"
, result4, result5);
Console.ReadLine();
}
}
}
|
委托链 。
前面讲过,委托在本质上仍然是一个类,我们用delegate关键字声明的所有委托都继承自System.MulticastDelegate。后者又是继承自System.Delegate类,System.Delegate类则继承自System.Object。一个委托可以绑定若干相同签名的方法形成一个委托链,委托链是一个委托实例的集合,它允许我们调用这个集合中的委托实例所代表的所有方法(对于有返回值的方法,委托链的返回值为链表中最后一个方法的返回值),在下面的例子我们定义的委托方法都没有返回值。我们可以用 GetInvocationList()方法获取委托链.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class
Program
{
static
void
Main(
string
[] args)
{
//Action 表示没有返回值的一类方法
Action<
int
,
int
> actionA = (x, y) =>
{
Console.WriteLine(
"x是{0},y是{1},他们的平方和是{2}"
, x, y, x * x + y * y);
};
actionA += (x, y) =>
{
Console.WriteLine(
"x是{0},y是{1},他们的平方差是{2}"
, x, y, x * x - y * y);
};
actionA(10, 5);
foreach
(var item
in
actionA.GetInvocationList())
Console.WriteLine(item.Method);
Console.ReadLine();
}
}
|
什么是事件 。
经常看到一种定义是:事件是一种特殊的委托,是对委托的封装。其实这种定义是很不严谨的。委托是一种数据类型,但是事件只是委托的实例,不能算是一种数据类型,所以说事件是一种特殊的委托是不准确的。如果这样定义:事件是一种特殊的委托实例,是对委托的封装。那么在C#中事件是如何定义并被使用的呢?其实事件从定义到使用要经过四个阶段.
•定义事件依赖的委托,并定义事件以及引发事件的方法,该步骤可以定义在事件发布器类中 。
•定义事件所依赖的事件方法,该步骤可以定义在事件订阅者类中 。
•如果有事件参数,该步骤可以定义在事件参数类中 。
•注册事件并引发事件,该步骤一般写在主程序中 。
一般来讲在事件定义过程中,各个方法的命名没有统一的标准,但我们可以参考微软在c#中的命名规范进行命名 。
建议事件委托命名为:事件+EventHandler。如果有额外的参数传递需定义自己的参数类型,参数类型的命名规范 :事件+EventHandler。比如,可以定义一个事件委托 public delegate void calcEventHandler(object sender,calcEventArgs e); .
定义一个事件变量如:public event calcEventHandler calc,
定义一个引发事件的方法如:public void onCalc(object sender,calcEventArgs e){} 。
建议方法名为 on+事件,就如同我们在开发web程序时,绑定的事件名有onClick,onLoad等一样.
参考看下面的例子,了解定义一个事件的一般过程,如果不需要传递事件的参数可以省去事件参数类的定义,使用系统预定义的EventArgs就可以了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/// <summary>
/// 主程序类
/// </summary>
class
Program
{
static
void
Main(
string
[] args)
{
eventPublish myEvent =
new
eventPublish();
eventSubscription myMethod =
new
eventSubscription();
//绑定方法 add 和 subtract,又称为对事件方法的注册 -=称为对事件方法的注销
myEvent.calc += myMethod.add;
myEvent.calc += myMethod.substract;
while
(
true
)
{
try
{
Console.WriteLine(
"请输入第一个整数数"
);
int
numA = Convert.ToInt16(Console.ReadLine());
Console.WriteLine(
"请输入第二个整数"
);
int
numB = Convert.ToInt16(Console.ReadLine());
calcEventArgs e =
new
calcEventArgs(numA, numB);
//在本例不需要sender参数,随意传递了字符串"sender"
myEvent.onCalc(
"sender"
, e);
}
catch
(Exception ex)
{
Console.WriteLine(
"出现错误,"
+ ex.Message);
}
}
}
}
/// <summary>
/// 定义一个事件发布器类
/// </summary>
class
eventPublish
{
//定义一个委托类型,委托名一般是 事件变量名+EventHandler
public
delegate
void
calcEventHander(
object
sender,calcEventArgs e);
//定义一个事件变量,其变量名为calc
public
event
calcEventHander calc;
//封装事件,对外定义了引发事件的方法,定义的引发方法名一般是 on+事件变量名
public
void
onCalc(
object
sender, calcEventArgs e)
{
if
(calc !=
null
)
calc(sender,e);
}
}
/// <summary>
/// 定义一个事件订阅者类(事件方法类)
/// </summary>
class
eventSubscription
{
public
void
add(
object
sender, calcEventArgs e)
{
Console.WriteLine(
"两数相加等于{0}"
, e.X + e.Y );
}
public
void
substract(
object
sender, calcEventArgs e)
{
Console.WriteLine(
"两数相减等于{0}"
, e.X - e.Y);
}
}
/// <summary>
/// 定义一个事件参数类
/// </summary>
class
calcEventArgs : EventArgs
{
private
int
_x;
private
int
_y;
public
calcEventArgs(
int
x,
int
y)
{
this
._x = x;
this
._y = y;
}
public
int
X
{
get
{
return
_x; }
}
public
int
Y
{
get
{
return
_y; }
}
}
|
我们将事件是对委托的封装,如果用ILDAS反编译可执行文件查看中间代码就可以非常明了的看出事件运行机制 。
如上图所示,事件calc,经.net运行时编译为中间语言后产生了一个private 的calc属性,同时也自动生成了add_calc和remove_calc方法,用于注册和注销订阅者方法。因为事件是被封装的,尽管calc属性是private,但在所以在发布器类内部可以用 calc(sender,e)这样的方法直接调用;但在主程序中如果这样使用就会出错,只能通过onCalc方法进行间接调用.
后记 。
本篇文章,一开始提出了什么是委托的疑问,通过引入几个方法来讲述委托是什么以加强对委托概念的理解。第二部分讲述了使用委托的四个步骤,并通过示例阐述了这几个步骤。第三部分讲述了委托使用的简化问题,通过使用泛型委托简化自定义委托,通过使用匿名委托可以简化定义委托方法。匿名委托是在定义委托的时候直接给出方法体,通过使用lambda表达式的类型推断可进一步简化委托的使用。第四部分讲述了委托链,通过绑定方法初始化委托,并通过+=绑定更多的委托方法。第五部分讲述了事件的定义和使用的四个步骤。当然委托的使用场景还有很多,比如通过BeginInvoke和EndInvoke进行异步调用,因不是本篇文章的重点,所以文章中没有提及.
以上内容是小编给大家介绍的C#中的委托数据类型简介,希望对大家有所帮助! 。
最后此篇关于C#中的委托数据类型简介的文章就讲到这里了,如果你想了解更多关于C#中的委托数据类型简介的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个加载 View 的 View ,需要将 View 推送到主导航 Controller 。 我已经为每个 View 设置了一个委托(delegate),并且基本上使我的调用沿着“链”返回到主导航
我通过 NSURLConnction 从服务器获取数据,并希望从获取的数组中填充表格 View 。数据出现在 NSURLConnection 委托(delegate)方法的日志中,但我意识到 numb
我已经将我用作标题 View 的 View 子类化,它里面有一些按钮委托(delegate),它工作得很好。 但是,我在 viewController 上方展示了一个 modalViewControl
我希望这听起来像是一个显而易见的问题,但是委托(delegate)返回类型是否也必须与其委托(delegate)的方法的返回类型相匹配? EG,像这样: public static void Save
我想使用 Kotlin 委托(delegate),但我不想在委托(delegate)人之外创建委托(delegate)。委托(delegate)的所有示例都如下所示: interface Worker
我有一个问题: - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInf
伙计们。我正在寻求帮助。这似乎是一个非常简单的任务,但我可以解决一整天。我正在尝试使用容器 View 创建侧面菜单。当用户按下“更多”按钮(barButtonItem)时,整个 View 向右滑动并出
我正在努力将 UIWebView 迁移到 WKWebView。我已经更改了所有委托(delegate)方法。我需要 WKWebView 委托(delegate)方法等于下面的 UIWebView 委托
我正在学习 VB.NET 中的委托(delegate),但对委托(delegate)类型感到困惑。在阅读有关委托(delegate)的内容时,我了解到委托(delegate)是一种数据类型,可以引用具
我有一个用 Objetive-C 构建的框架。该框架用于连接蓝牙设备并与之交互。 在演示代码中,Objetive-C 委托(delegate)函数如下所示。演示代码由框架创建者提供。 -(void)b
//NewCharts.h #import @interface NewCharts : UIViewController @property(nonatomic,retain)IBOutlet U
我正在努力了解 async/await 并认为我确实了解有关用法的一些事情。但仍然不太清楚在下面的场景中实际好处是什么。 查看 Task.Run 用法。第一种方法使用普通委托(delegate)并使用
我已经尝试了在我的网站上使用 openID 委托(delegate)的所有可能选项,但没有一个方法对我有用。 我的 HTML 文件的 head 部分有“link rel”标签。 我在 HTML 文件的
如何快速创建一个委托(delegate),即 NSUserNotificationCenterDelegate? 最佳答案 这里有一些关于两个 View Controller 之间委托(delegat
我有一个带有数据源的 NSComboBox,当您单击三角形并通过单击它选择其中一个项目时,它可以完美运行。但是,我还希望它允许用户在框中键入以使用自动完成来选择名称。目前,当用户键入时,我希望选择的项
我在代码中定义了以下类和委托(delegate)(为简洁起见,剪掉了许多其他行)。 Public Delegate Sub TimerCallback(canceled As Boolean) Pub
我使用 ansible 2.1 并且我想使用 delegate_to 向一组主机运行命令。我使用 localhost 作为主机参数,并且我想将“touch”命令委托(delegate)给两个 cls
我想通过重载为我的类实现几个构造函数。据我了解,遵循 DRY 原则的惯用方式是使用一种称为委托(delegate)构造函数的功能。我也看到了关于在任何地方使用引用参数并不惜一切代价避免使用指针的想法,
代表们会导致内存泄漏吗? 我的意思是,例如如果一个类A包含一个ADelegate,并且后者指向BMethod(属于B类),这可以防止GC收集A类或B类吗? 如果是这样,我们如何“释放”代表(设置ADe
委托(delegate)命令和路由命令有什么区别? 我读了一些文章说在 MVVM 上使用委托(delegate)命令而不是路由命令。 那么当我们使用 MVVM 时,Delegate Command 相
我是一名优秀的程序员,十分优秀!