如何解析.NET中容易混淆的委托与接口,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
昨天在和一位朋友讨论到委托与接口的问题,一开始我觉得很不可思议,这两个东西的概念怎么会混淆呢?要混淆也是接口和抽象类,委托和事件相混淆啊!但是着我的一个例子我马上意识到很有可能因为我将要表现的这个例子,让很多朋友混淆了委托与接口的用途.所以我想通过这篇文章试图说明白委托和接口的概念和用途,其实他们俩的差别还是很大的.
委托:
委托是一种定义方法签名的类型。当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。您可以通过委托实例调用方法。
委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。您可以创建一个自定义方法,当发生特定事件时某个类(例如 Windows 控件)就可以调用您的方法.
委托具有以下特点:
委托类似于 C++ 函数指针,但它们是类型安全的。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不必与委托签名完全匹配。有关更多信息,请参见在委托中使用变体(C# 和 Visual Basic)。
C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。这些功能统称为匿名函数。有关 Lambda 表达式的更多信息,请参见Anonymous Functions (C# Programming Guide)。
接口:
接口描述的是可属于任何类或结构的一组相关功能。接口可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。接口不能包含字段。接口成员一定是公共的。
当类或结构继承接口时,意味着该类或结构为该接口定义的所有成员提供实现。接口本身不提供类或结构能够以继承基类功能的方式继承的任何功能。但是,如果基类实现接口,派生类将继承该实现。
类和结构可以按照类继承基类或结构的类似方式继承接口,但有两个例外:
类或结构可继承多个接口。
类或结构继承接口时,仅继承方法名称和签名,因为接口本身不包含实现。
接口具有下列属性:
接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
不能直接实例化接口。
接口可以包含事件、索引器、方法和属性。
接口不包含方法的实现。
类和结构可从多个接口继承。
接口自身可从多个接口继承。
正文开始
在写这些文字的时候我又将以上的各个概念熟悉了一遍,以防自己把自己忽悠混淆了.所以不适合群众请尽快退散.另外如果您看完上面的定义和特征后就从两者的混淆中走了出来,您也可以尝试继续往下看.
首先,关于委托的用法,我们可以这样使用:
以下是代码片段:
public int Calculate(Func del) { int a = 1, b = 2; return del(a, b); }
我们可以通过传不同的Func来改变整个方法的结果.
以下是代码片段:
public int Add(int a, int b) { return a + b; } public int Sub(int a, int b) { return a - b; } //调用方法如下 public void TestMethod() { int result = Calculate(Add); //the result is 3 int anotherResult = Calculate(Sub); //the result is -1 }
首先我在Calculate方法中已经确定了2个数的值,并且包括在该方法当中.在输出结果的时候能明显看出传递的委托不同,其结果也不同.我们使用委托来改变方法的执行内容,我们不但可以改变其方法的内容,也可以在执行该方法的时候顺便做点什么(比如说做个日志记录).
噢,可能您觉得二者容易混淆的地方在于..我还是举个例子比较好解释.
以下是代码片段:
public interface ICal { int Calculate(int a, int b); } //有多个类实现了ICal接口. public class Add : ICal { public int Calculate(int a, int b) { return a + b; } } public class Sub : ICal { public int Calculate(int a, int b) { return a - b; } } //然后通过调用不同类来获取不同的方法 public static void Main() { ICal cal = new Add(); //ICal=new Sub(); Console.Write(cal.Calculate(1, 2)); }
讲解一下,通过上面的例子我们可以知道在创建一个具有计算功能(Calculate)的接口ICal之后,产生了两个具有计算功能的具体类,分别是Add和Sub.为了要获得结果,我们创建了一个需要有计算功能的”坑”,并赋予能与此”坑”相匹配的类Add(或Sub),***从该坑中调用Calculate的结果就行.
貌似说的过去?好,那么我至少要让你觉得有个适用范围吧!看下面的例子.
比如有个Person类的数组arr.这时候我们可以通过委托的方法实现arr的排序.可是系统怎么知道2个Person哪个排在前面,哪个该排在后面?这时候我们就可以传进一个委托来告诉系统Peron类的大小.
以下是代码片段:
arr.Sort(p => { p.ID });
该lambda表达式意思是丢给该Sort方法一个排序的Key(此key能够进行大小比较),那么Sort就可以根据此key来进行比较.那通过接口呢?首先得创建一个继承自IComparer的类,我就拿本身继承它吧.
好吧,它本来是很麻烦的:
以下是代码片段:
private int SortDelegate(Person p) { return p.ID; } public void TestMethod() { arr.Sort(new Func(SortDelegate)); }
但是我们要承认C# 3.0带给我们的便利.
现在,我们要让Person类实现接口的规定.
以下是代码片段:
public int Compare(Person x, Person y) { //假设person的ID是int类型 return x.ID - y.ID; }
那么我们的实现方法就可能是这样:
以下是代码片段:
arr.Sort((new Person() as IComparer) comp);
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。