c# – 如何以正确的方式使用委托/了解委托
使用 – C#(.Net Framework 4.5,Visual Studio 2012)
我试着理解像代表这样的主题,目前我有几点,必须为我澄清. 据我所知,我必须做一些使用委托的事情: >创建一些实体用于它(需要创建一些委托) 所有描述如下所示 问题 – 我是否正确理解了所有或者我错了 – 请澄清一下. 另外一个关于DELEGATE的问题 – 哪里更好地将代码放在DELEGATE中 – 在Console C#应用程序中我可以在任何使用过的Namespace的地方创建它 – 我可以在下面看到. 但也许有一些建议/要求不仅为控制台应用程序而且为WinForms,WPF等放置委托. 这个主题对我来说是新的,我花了一天时间来理解它,但仍然有点(或更多)与此相混淆,最后创建这篇文章以获得更好和清晰的理解.认为这是非常强大的东西. 编辑 namespace SimpleCSharpApp { delegate void myDelagate (); } 解决方法
Ho-ho ..你有些搞砸了.直到我看到VS的屏幕截图,并在“委托”声明下带有红色下划线,我还没有完全掌握你想要说明的问题.
首先,暂时忘掉公共无效委托zczcxxzc行.这有点特别.首先,让我们看一些代表的标准种类*). 最基本的两个是: > System.Action 两者都是通用的,并且第一次看到它们的签名,它们看起来可能过于复杂.但是,它们真的非常简单. 首先,让我们限制裸,无参数,System.Action. private static void myFunction1() { Console.WriteLine("Hello!"); } private static void myFunction2() { Console.WriteLine("Bye!"); } private static void myFunction0() { return; } ... // in some function,i.e. Main() Action myDelegate = null; myDelegate = new Action( myFunction1 ); myDelegate(); // writes "Hello!" myDelegate = new Action( myFunction2 ); myDelegate(); // writes "Bye!" myDelegate = new Action( myFunction3 ); myDelegate(); // does "nothing" 就像“int”包含一个数字,“string” – 文本,“委托”包含有关“可调用的东西”的信息,或者,使用某些术语,“可调用的东西”. 首先,我创建了一个记住“myFunction1”的“Action”类型的委托.然后我调用/调用该委托 – 它导致被记住的函数被调用. 然后,我创建一个类型为“Action”的委托,记住“myFunction2”.然后我调用/调用该委托 – 它导致被记住的函数被调用. 最后,它记住了“myFunction3”.然后我调用/调用该委托 – 它导致被记住的函数被调用,没有任何反应 – 但只是因为目标函数什么也没做. 请注意,我故意说“创建了一个代表”.每次执行新Action时,都会创建一个新委托. “委托”只是一个对象,如String“foo”或float [] {1.2,4.5}. 另请注意,此处使用的创建委托的完整语法是新的Action(…).就像创建任何对象一样 – 新的typename构造参数.另一个标志,“代表”只是一个对象. 另外需要注意的是我没有编写新的Action(myFunction1()).我不想调用该方法并获取其结果并将该结果提供给Action的构造函数.我写了新的Action(myFunction1).我把函数本身给了构造函数. 那么,什么是“行动”呢? System.Action是一个类.像String,或Socket或WebClient.这里没什么特别的.所以,我们有一个“类”,它的对象可以记住应该被调用的函数.凉. 因此,有些人将代表与“函数指针”进行比较.但那并不完全正确.函数指针可以记住要调用的函数.代表们可以记住要调用的方法.记得区别吗?在上面的例子中,我故意在每个myFunction上写静态.这些可以被称为无对象/无目标.你需要他们的名字,你可以从任何地方打电话给他们.要打电话给他们,一个简单的哑指针就足够了. 现在,代表们可以做得更多.他们可以研究方法.但是需要针对对象调用方法. class GuineaPig { public static void Squeak() { Console.WriteLine("Ieek!"); } public void Well() { Console.WriteLine("actually"); } public void IDontKnow() { Console.WriteLine("what they do"); } } GuineaPig.Squeak(); // says 'ieek' Action myDelegate = null; myDelegate = new Action( GuineaPig.Squeak ); myDelegate(); // writes "ieek" // GuineaPig.Well(); // cannot do! // myDelegate = new Action( GuineaPig.Well ); // cannot do! 好吧,在其他类中创建一个静态函数的委托很容易 – 只需要确切地说什么是函数来自什么类.再次就像打电话一样,但没有括号. 但是,如果您尝试取消注释对非静态方法的引用,它将无法编译.看看GuineaPig.Well – 这很明显.它不是静态的,需要针对OBJECT而不是CLASS进行调用.出于同样的原因,无法创建委托.我们来解决这个问题: class GuineaPig { public void Well() { Console.WriteLine("actually"); } public void IDontKnow() { Console.WriteLine("what they do"); } } GuineaPig myPiggie = new GuineaPig(); myPiggie.Well(); // ok! writes "actually" Action myDelegate = null; myDelegate = new Action( myPiggie.Well ); // ok! myDelegate(); // ok! writes "actually". 请注意在创建委托期间如何将classname替换为objectvariable.语法被保留:就像调用一样,但没有parens.但是,关于“方法”与“功能”的所有大惊小怪…… 代理人不仅可以存储要调用的“方法”,还可以存储调用它们的对象. class GuineaPig { public string Name; public void Well() { Console.WriteLine("I'm " + Name); } } GuineaPig myPiggie1 = new GuineaPig { Name = "Bubba" }; GuineaPig myPiggie2 = new GuineaPig { Name = "Lassie" }; Action myDelegate = null; myDelegate = new Action( myPiggie1.Well ); myDelegate(); // -> Bubba myDelegate = new Action( myPiggie2.Well ); myDelegate(); // -> Lassie myPiggie1 = myPiggie2 = null; myDelegate(); // -> Lassie 现在,这是普通函数指针无法做到的. (尽管你可以使用非常智能的函数指针……但是,让我们离开它). 注意如何在“pig#2”上调用“Well”的事实存储在委托对象中. “myPiggie2”变量无关紧要.我可以使它无效.代表记住了目标和方法. System.Action只是其中之一.它是最简单的,没有参数,没有返回..但是它们中有很多,它们可以获取参数(Action< string,int>)它们可以返回值(Func< int>)或两者(Func< string,int>) .然而,不断说Func< int,float,string,int,bool,decimal>有点……模糊不清 好.让我们终于明白了这一切的唠叨.对不起,如果你知道所有这些,但我想要清楚. “代表”就是要记住“目标”和“方法”.实际上,如果你在调试器中检查一个委托(或检查Intellisense在“点”之后说的内容),你会看到两个属性,Target和Method.他们正是他们的名字所代表的. 让我们假设您想要创建自己的委托类型.一种不会被称为Func< int,Zonk,string>的类型,而是“MyStudentFilteringDelegate”. 现在,重点是,在C#中你不能轻易地获取函数的&(地址),也不能重载operator().这导致您无法编写自己的委托类. 你不能只写: class MyStudentFilteringDelegate { public object Target; public somethingstrange* MethodPointer; // other code } 因为,即使你真的设法遵循这个想法,最后在某个地方你会发现: MyDelegate dd = new MyDelegate ( ... ); dd(); // is just impossible!!! 至少,在当前的C#版本4.5或5中. 你不能重载“call”/“invoke”操作符,因此你将无法完全实现自己的,自定义命名的委托类型.你永远都会被动作和Funcs困住. 现在回想起公共无效代表xxx下面的红色下划线我请你暂时忘记. public bool delegate MyStudentFilteringDelegate( Student stud ); 此行不会创建任何委托.该行定义了委托的类型.它与Func< Student,bool>完全相同,带有自定义名称. *) 实际上,编译器将行转换为: public class MyStudentFilteringDelegate : some_framework_Delegate_class { // object Target {get;} - inherited from base class // MethodInfo Method {get;} - inherited from base class,too } 所以它是一个类,所以你现在可以创建一个委托对象: var dd = new MyStudentFilteringDelegate ( ... ); // like normal class! dd(); // ok!; 由于类是特殊的,编译器生成的,它可以破坏规则.它的’call’/’invoke’运算符被重载,所以你可以“调用”委托,因为它是一个方法. 请注意,尽管有一些奇怪的表示法: public bool delegate MyStudentFilteringDelegate( Student stud ); MyStudentFilteringDelegate是一个类,就像Action或Func或String或WebClient一样. delegate关键字只是编译器的标记,以便知道它应该应用于该行的转换以生成适当的“委托类型”(类). 现在,要真正回答你的另一个问题: 在您放置委托类型声明的地方真的无关紧要.你可以在任何你喜欢的地方写公共空委托XYZ(…).就像你可以在任何地方放置一个类声明一样. 您可以将类声明放在默认(无命名空间)范围,某个命名空间或类中.因此,由于委托类型只是一个类,您还可以在默认(无命名空间)范围,某个命名空间或类内部处理新的委托类型: public class Xc {} public void delegate Xd(); namespace WTF { public class Xc {} public void delegate Xd(); class Whatever { public class Xc {} public void delegate Xd(); } } 请注意,我完全故意将它们命名为相同.那不是错误.首先命名为:: global.Xc和:: global.Xd,第二对命名为WTF.Xc和WTF.Xd,最后一对命名为WTF.Whatever.Xc和WTF.Whatever.Xd.就像普通的clases一样. 要确定放置这些声明的位置,请使用与您用于类的规则相同的规则. IE浏览器.如果您将文本处理类放在命名空间MyApp.Text.Parsing中,那么与该文本处理相关的所有委托类型也应该位于该命名空间中.但是,即便如此,这纯粹是化妆和组织的.在适合您的任何范围内放置/定义它们. 编辑:*)实际上,从历史上看,它是完全相反的.委托关键字和编译器技巧比Action和Func类旧.在.Net 2.0中,Action / Func不存在.创建/使用委托的唯一方法是定义自己的新委托类型(或在系统的名称空间深处找到/猜测一些合适的委托类型).请记住,每个新的委托类型都是一个新类.不能转换为任何其他类,甚至不能同样看起来.令人沮丧的是令人沮丧且难以保持,在.Net 3.5中,他们最终在框架中包含了“通用通用委托类型”.从那时起,Action / Func越来越多地被使用,因为即使它们更难阅读,它们也是通用的. System.Func<学生,布尔>可以在任何地方传递,并且你没有问题,来自一个库的’bool委托StudentFilter()与另一个库中的bobo委托StudentSelector()`没有匹配. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |