使用-C#(.Net Framework 4.5,Visual Studio 2012)
我试图理解像Delegate这样的主题,目前我的观点不多,我需要澄清一下。
我在互联网上发现了许多不同的信息来描述如何使用它,但是对我来说,理解这个主题有点复杂。
据我了解,我必须做一些使用委托的事情:
创建一些实体来使用它(需要创建一些委托)
声明一个委托类型
创建一些我要委托的方法
在主类中,使用具有实体的必需方法调用委托(从第一点开始)
全部描述如下
问题-我是否正确理解所有内容,或者我错了-请澄清一下。
还有一个关于DELEGATE的问题-在控制台C#应用程序中,什么地方最好用DELEGATE放置代码,我可以在使用的命名空间的任何位置创建它,如下所示。
但是,也许不仅对控制台应用程序而且对于WinForms,WPF等都放置委托的一些建议/要求。
这个主题对我来说是新的,我花了一天的时间来理解它,但仍然对此感到困惑(或更多),最后创建这篇文章以更好地理解。认为这是非常强大的东西。
编辑
namespace SimpleCSharpApp
{
delegate void myDelagate ();
}
参考方案
呵呵..你搞砸了。在我看到VS的屏幕快照的“ delegate”声明下带有红色下划线的屏幕截图之前,我还不太了解您要解决的问题。
首先,暂时忽略public void delegate zczcxxzc
行。这有点特别。首先,让我们看一些标准类型的委托。
最基本的两个是:
System.Action
System.Func
两者都是通用的,并且第一次看它们的签名,它们似乎过于复杂。但是,它们确实非常简单。
对于初学者,让我们将其限制为裸,无参数的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”(文本)一样,“ delegate”保存关于“可调用的东西”或使用某些术语“可调用的东西”的信息。
首先,我创建一个记住“ myFunction1”的“ Action”类型的委托。然后,我调用/调用该委托-导致调用记住的函数。
然后,创建一个记住“ myFunction2”的“ Action”类型的委托。然后,我调用/调用该委托-导致调用记住的函数。
最后,我创建一个记住“ myFunction3”的“ Action”类型的委托。然后,我调用/调用该委托-它导致调用已记住的函数,并且什么也没有发生-只是因为目标函数什么都不做。
请注意,我故意说“创建了代表”。每次执行new Action
时,都会创建一个新的委托。 “委托”只是一个对象,例如字符串“ foo”或float [] {1.2,4.5}。
另外,请注意,此处使用的创建委托的完整语法为new Action(...)
。就像创建任何对象一样-新+类型名+构造参数。另一个代表“委托”只是一个对象。
要注意的另一件事是我没有写new Action( myFunction1() )
。我不想调用该方法并获取其结果并将该结果提供给Action的构造函数。我写了new Action( myFunction1 )
。我把函数本身交给了构造函数。
但是,什么是“动作”? System.Action是一个类。像字符串,或套接字或WebClient。这里没什么特别的。因此,我们有一个“类”,其对象可以记住应调用的功能。凉。
因此,有些比较代表“函数指针”。但这并不完全正确。函数指针可以记住要调用的函数。代表们可以记住要调用的方法。还记得区别吗?在上面的示例中,我故意在每个static
处编写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
-很明显。它不是静态的,需要针对对象而不是类进行调用。由于同样的原因,无法创建委托。让我们修复一下:
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".
请注意,在创建委托期间,如何用objectvariable替换classname。语法保留下来:就像调用一样,但没有括号。但是,关于“方法”与“功能”的大惊小怪的是什么。
代表不仅可以存储要调用的“什么方法”,还可以存储调用它们的对象。
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,int,bool,decimal>
来表达是有点……晦涩的。
好。让我们终于弄明白所有这些胡言乱语。抱歉,如果您知道所有这些,但我想澄清一下。
“委托”就是关于记住“目标”和“方法”的全部。实际上,如果您曾经在调试器中检查委托(或检查Intellisense在“点”之后的内容),您将看到两个属性,Target和Method。他们就是他们名字的意思。
假设您要创建自己的委托类型。不会被称为Func<int,int,int,bool,bool,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”运算符,因此您将无法完全实现自己的,自定义名称的委托类型。您将永远被困在Actions和Funcs中。
现在回想一下我要求您暂时忘记的public void delegate 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
关键字只是一个标记,编译器可以知道该标记应对该行应用哪种转换以生成适当的“委托类型”(类)。
现在,要实际回答您的其他问题:
放置委托类型声明的位置确实无关紧要。您可以在任何喜欢的地方写public void 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
。就像正常情况一样。
要决定将这些声明放在何处,请使用与类相同的规则。就是如果将文本处理类放在命名空间MyApp.Text.Parsing
中,则与该文本处理相关的所有委托类型也应位于该命名空间中。但是,即使如此,这纯粹是装饰性和组织性的。将它们放置/定义在您认为合适的任何范围内。
编辑:
*)实际上,从历史上看,它全都是其他方式。 delegate
关键字和编译器技巧比Action和Func类更早。在.Net 2.0中,Action / Func不存在。创建/使用委托的唯一方法是定义自己的新委托类型(或在系统名称空间的深处查找/猜测一些合适的委托类型)。请记住,每个新的委托类型都是一个新的类。不能转换为任何其他类,甚至外观也不相似。它是如此令人厌烦且难以维护,以至于在.Net 3.5中,他们最终在框架中包括了“通用通用委托类型”。从那时起,Action / Func越来越多地被使用,因为即使它们更难阅读,它们仍然是通用的。可以“随处”传递System.Func<Student,bool>
,您不会遇到另一个问题:“ bool委托StudentFilter()from one library does not match
bool委托StudentSelector()`”的问题。
我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…
改造正在返回一个空的响应主体 - java我正在尝试使用Retrofit和Gson解析一些JSON。但是,我得到的响应机构是空的。当我尝试从对象中打印信息时,出现NullPointerException。我确保URL正确,并且我也确保POJO也正确。我正在使用jsonschema2pojo来帮助创建POJO类。这是我要解析的JSON{ "?xml": { "@versi…
每个文件合并后添加换行 - python我有很多类似以下内容的JSON文件:例如。1.json{"name": "one", "description": "testDescription...", "comment": ""} test.json{"name"…
您如何在列表内部调用一个字符串位置? - python我一直在做迷宫游戏。我首先决定制作一个迷你教程。游戏开发才刚刚开始,现在我正在尝试使其向上发展。我正在尝试更改PlayerAre变量,但是它不起作用。我试过放在列表内和列表外。maze = ["o","*","*","*","*","*",…
Mongo汇总 - javascript我的收藏中有以下文件{ "_id": ObjectId("54490b8104f7142f22ecc97f"), "title": "Sample1", "slug": "samplenews", "cat": …