如何使用正确的方法/了解delagates代表 [英] How to use delegates in correct way / Understanding delagates

查看:341
本文介绍了如何使用正确的方法/了解delagates代表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 - C#(.NET框架4.5时,Visual Studio 2012)



我试着去理解这样的主题像委派,目前我有几个点,那一定是澄清我。
我发现互联网有很多不同的信息,描述了如何使用它,但它是一个有点复杂,理解我这个主题。



在我明白我必须做一些事情了使用委托:




  • 创建为它工作的一些实体(需要创造一些代表)

  • 声明一个委托类型

  • 创建一些方法,我称之为委托

  • 在与所需的方法主类调用委托即使用实体(从第一个点)



所有的描述我在下面





问题 - 我是正确理解全部或者也许我错了 - 请澄清



另一种问题有关DELEGATE - 在哪里。不如把代码DELEGATE - 在控制台C#应用程序,我可以使用的命名空间中的任何地方创建它 - 我可以在下面显示





但也许有一些推荐/用于放置代表不仅要求对于控制台应用程序也为的WinForms,WPF等。



这主题是新的,我和我花了一天的理解,但还是有点(或更)与此相混淆,终于创造这个职位更好,清晰的认识。认为这是非常强大的东西。



修改



 命名空间SimpleCSharpApp 
{
委托无效myDelagate();
}


解决方案

浩浩你..已经得到的东西弄乱了。我也不太明白你正在尝试的状态,直到我看到VS下委托申报红色下划线的截图什么问题。



首先,忘掉公共无效委托zczcxxzc 片刻线。这是有些特殊。首先,让我们来看看一些标准的各种*)代表



这两个最基本的是:




  • System.Action

  • System.Func



两者是通用的,看他们首次签名,他们可能看起来过于复杂。但是,他们真的很简单。



首先,让我们来限制裸露,无参数, System.Action

 私有静态无效myFunction1(){Console.WriteLine(你好!); } 
私有静态无效myFunction2(){Console.WriteLine(再见!); }
私有静态无效myFunction0(){返回; }

... //一些功能,即主()
行动myDelegate = NULL;

myDelegate =新的行动(myFunction1);
myDelegate(); //写道:你好!

myDelegate =新的行动(myFunction2);
myDelegate(); //写道:再见!

myDelegate =新的行动(myFunction3);
myDelegate(); //做无中生有



就像INT持有数量,串 - 文字,一个代表认为有关可调用的东西,或者用一些术语,可调用的东西。



首先,我创建一个委托的回忆myFunction1式的行动。然后,我调用/调用该委托 - 它导致记忆被调用函数



然后,我的创建委托键入行动该记住myFunction2。然后,我调用/调用该委托 - 它导致记忆被调用函数



最后,我创建一个委托类型行动该记住myFunction3。然后,我调用/调用委托 - 它导致记忆被调用函数,并没有任何反应 - 但仅仅是因为目标函数什么也没做。



请注意,我故意说创造了一个代表。每次执行新的动作,创建一个新的委托。 A代表只是一个对象,如字符串foo或浮动[] {1.2,4.5}。



另外请注意,用于创建代表完整的语法这里是新动作(...)。就像创建任何对象 - 新的类型名称+ +施工参数。然而,另一个迹象,表明一个代表只是一个对象。



另外要注意的是,我没有写新动作(myFunction1() )。我不想调用该方法,并得到其结果和该结果给行动的构造函数。我写了新动作(myFunction1)。我给的函数本身以构造。



不过,那么,什么是操作? System.Action是一类。如String,或Socket或Web客户端。这里没有什么特别。因此,我们有一个类,其对象可以记住什么功能,应待调用。酷。



因此,有些比较代表为函数指针。但是,这并不完全正确。函数指针还记得什么功能即可调用。代表们还记得是什么方式即可调用。记得有什么区别?在上面我举的例子,我特意写了静态在每个 myFunction的。那些可以被称为对象以下/目标少。你只需要他们的名字,你可以从任何地方调用它们。打电话给他们,一个简单的哑指针就足够了。



现在,代表们可以做得更多。他们可以在方法工作。但方法都需要对一个对象被调用。

 类豚鼠
{
公共静态无效佳乐(){Console.WriteLine(Ieek!); }

公共无效井(){Console.WriteLine(实际); }
公共无效IDontKnow(){Console.WriteLine(他们做了什么); }
}

GuineaPig.Squeak(); //说'ieek'

行动myDelegate = NULL;
myDelegate =新的行动(GuineaPig.Squeak);
myDelegate(); //写ieek

// GuineaPig.Well(); // 不会!
// myDelegate =新的行动(GuineaPig.Well); // 不会!



好吧,作出委托的其他类的静态函数是很容易 - 刚刚说什么 - 功能 - 从 - 什么类。再次就像打电话,但没有括号。



但是,如果您尝试取消注释非静态方法的引用,它不会编译。综观 GuineaPig.Well - 这是显而易见的。这不是一成不变的,它需要调用针对对象,而不是类。对于同样的原因,委托无法创建。让我们来解决这个问题:

 类豚鼠
{
公共无效井(){Console.WriteLine(其实); }
公共无效IDontKnow(){Console.WriteLine(他们做了什么); }
}

豚鼠myPiggie =新豚鼠();

myPiggie.Well(); // 好!写道:实际上是

行动myDelegate = NULL;
myDelegate =新的行动(myPiggie.Well); // 好!

myDelegate(); // 好!写道:实际上是。

请注意如何在类名创建委托的过程中与objectvariable取代。语法保留:就像打电话,但没有括号。但是,什么是所有关于办法与功能。



代表们不仅可以存储被称为用什么方法,但也大惊小怪什么。对象以他们呼吁

 类豚鼠
{
公共字符串名称;

公共无效井(){Console.WriteLine(我+姓名); }
}

豚鼠myPiggie1 =新豚鼠{名称=布巴};
豚鼠myPiggie2 =新豚鼠{名称=灵犬莱西};

行动myDelegate = NULL;

myDelegate =新的行动(myPiggie1.Well);
myDelegate(); // - >布巴

myDelegate =新的行动(myPiggie2.Well);
myDelegate(); // - >莱茜

myPiggie1 = myPiggie2 = NULL;

myDelegate(); // - >莱茜

现在这是你不能用普通的函数指针做。 (虽然有非常聪明的函数指针,你可以..但是,让我们离开这一点)。



请注意是如何的事实,好是在猪#2被称为被存放在委托对象中。在myPiggie2变量是不相关的。我可能抵消它。该代表还记得这两个目标和方法。



System.Action仅仅是家庭的一员。这是simpliest,无参数,可以没有回报。但也有很多人,他们可以得到的参数(动作<字符串,整数> ),他们可以返回值( Func键< INT> )或两个( Func键<字符串,整数> )。然而,在Func键LT 的条款和不断而言,整型,浮点,字符串,INT,INT,BOOL,小数> 是有点......模糊

$ B $。 b

确定。让我们最后得到这一切的咿呀学语的地步。很抱歉,如果你知道了这一切,但我想清楚了。



A代表是所有关于记忆的目标和方法。事实上,如果你检查在调试器委托(或检查什么智能感知点后说),你会看到两个属性,目标和方法。他们是自己的名字只是站在什么。



让我们想象一下你想创建自己的类型委托的。这就不叫 Func键474上的类型; INT,INT,INT,BOOL,BOOL,使...非常吃惊,串方式> ,而是MyStudentFilteringDelegate



现在,整点是,在C#中的你不能把&放大器;函数(地址)容易,并且还您不能重载运算符()。这导致您暂时无法写自己的委托类的类



您不能只是写:

 类MyStudentFilteringDelegate 
{
公共对象目标;
公共somethingstrange * MethodPointer;

//其他码
}



,因为即使你居然成功地遵循这一想法,在结束的地方,你会发现:

  MyDelegate DD =新的MyDelegate(... ); 
DD(); //仅仅是不可能的!



至少,在目前的C#版本4.5或5。



您就不能超载通话/调用操作符,因此你将无法充分实现自己的,自定义命名,委托类型。你会在行动和funcs中被卡住,直到永远。



现在还记得,公共无效委托XXX下红色下划线我让你暂时忘却

 公共BOOL委托MyStudentFilteringDelegate(学生螺柱); 

这行的不会产生任何代表。这一行定义了类型的委托的。这是完全一样的 Func键<学生,布尔> ,用自定义名称。 *)



在事实上,编译器将线路为:

 公共类MyStudentFilteringDelegate:some_framework_Delegate_class 
{
//对象target {获得;} - 从基类
// MethodInfo的方法{得到继承; - 从基类继承,太$ b $} b}

所以,这是一个的,然后这样就可以了现在创建一个代表对象:

  VAR DD =新MyStudentFilteringDelegate(...); //像正常上课! 
DD(); // 好!;



由于类是特殊的,编译器生成的,它可以打破规则。 。这是'叫'/'调用'操作符重载,这样你就可以呼的代表,因为它是一种方法



请注意,尽管奇怪的符号:

 公共BOOL委托MyStudentFilteringDelegate(学生螺柱); 



MyStudentFilteringDelegate ,就像Action或者Func键或字符串或Web客户端的。在委托关键字仅仅是一个编译器知道它应该适用何种转变到该行生成适当的委托类型(类)的标记。



现在,实际上回答您的其他问题:



真正不相干你把委托类型声明的。你可以写公共无效委托某某(...)您想要的位置。正如你可能放置的类声明的任何地方。



您可以将类声明的默认的(无命名空间)的范围,在某些命名空间或类中。因此,随着委托类型就是一个类,你也可以在默认的(无命名空间)范围delcare新的委托类型,在一些空间,或者类中:

 公共类XC {} 
公共无效委托的Xd();

命名空间WTF {
公共类XC {}
公共无效委托的Xd();

级无论{
公共类XC {}
公共无效委托的Xd();
}
}

请注意,我完全故意将它们命名为相同。这是没有错误。首先被命名为 :: global.Xc :: global.Xd ,第二对被命名为 WTF.Xc WTF.Xd 并最终对被命名为 WTF.Whatever.Xc WTF.Whatever.Xd 。就像正常的clases。



要决定在何处放置这些声明,如您使用类使用相同的规则。 IE浏览器。如果你把文字处理类的命名空间 MyApp.Text.Parsing ,那么所有与该文本处理的delegatetypes应该坐在该命名空间了。但是,即便如此,那纯粹是化妆用和组织。地方/在它使任何余地,你感觉他们定义



编辑:
*)实际上,从历史上看,这是周围所有其他的方式。在委托关键字和编译器的诀窍是的老年比Action和Func键类。在NET 2.0,动作/ FUNC并不存在。只有这样,才能建立/使用委托是定义你自己的新的委托类型(或查找/系统的命名空间某处深猜测一些合适的一个)。请记住,每一个新的委托类型是一个新类。无法转换为其他类,甚至没有类似的前瞻性。它是如此令人沮丧的无聊和难以十个分量,,在NET 3.5的他们终于列入框架的通用泛型委托类型。从该时间点,动作/ FUNC日益经常使用,因为即使它们更难读,它们是..普遍。 System.Func<学生,布尔> 可以随时随地过去了,你没有那个'bool的委托StudentFilter()从问题一个库不会从anoother一个匹配布尔委托StudentSelector()`。


use - C# (.Net Framework 4.5, Visual Studio 2012)

I try to understand such theme like Delegate, and currently I have few points, that must be clarified for me. I found a lot of different information in internet that describe how to use it, but it's a little bit complicated to understanding for me this theme.

As I understand I must to do few thing for using delegate:

  • Create some entity for work with it (that require creating some delegate)
  • Declare a delegate type
  • Create some method where I call to delegate
  • In main class call delegate with required method that use entity (from first point)

all described I show below

The question - am I correctly understand all or maybe I'm wrong - please clarify it.

Also another question regarding DELEGATE - where is better to put code with DELEGATE - in Console C# application I can create it in any place of used Namespace - as I can show below.

But maybe there is some recommendation/requirements for placing delegate not only for Console application but also for WinForms, WPF etc.

This theme is new for me and I spend a day for understanding it, but still a little bit (or a more) confused with this, finally create this post for better and clear understanding. think it's very powerfull stuff.

EDIT

namespace SimpleCSharpApp
{
   delegate void myDelagate ();
}

解决方案

Ho-ho.. you've got something messed up. I didn't quite grasp what problem you are trying to state until I saw the screenshot from VS with red underline under "delegate" declaration.

First, forget about the public void delegate zczcxxzc line for a moment. It is somewhat special. First, let's see some standard kinds *) of delegates.

The two most basic ones are:

  • System.Action
  • System.Func

Both are generic and looking at their signature for the first time, they may seem overly complex. But, they are really very simple.

For starters, let's limit to bare, parameterless, 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"

Just like "int" holds a number, "string" - text, a "delegate" holds information about "something callable", or, to use some terminology, "something invokable".

First, I create a delegate of type "Action" that remembers "myFunction1". Then I invoke/call that delegate - it results in the remembered function being called.

Then, I create a delegate of type "Action" that remembers "myFunction2". Then I invoke/call that delegate - it results in the remembered function being called.

Finally, I create a delegate of type "Action" that remembers "myFunction3". Then I invoke/call that delegate - it results in the remembered function being called, and nothing happens - but only because the target function did nothing.

Please note that I deliberately say "created a delegate". Each time a new Action is executed, a new delegate is created. A "delegate" is just an object, like String "foo" or float[] {1.2, 4.5}.

Also, note that the full syntax for creating delegates used here is new Action(...). Just like creating any object - new + typename + construction parameters. Yet another sign that a "delegate" is just an object.

Another thing to note is that I did not write new Action( myFunction1() ). I did not want to CALL the method and get its result and give that result to the constructor of Action. I wrote new Action( myFunction1 ). I gave the function itself to the constructor.

But, then, what is an "Action"? System.Action is a class. Like String, or Socket or WebClient. Nothing special here. So, we have a "class" whose objects can remember what-function-should-be-called. Cool.

Therefore some compare delegates to "function pointers". But that's not fully right. Function pointers can remember what function to call. Delegates can remember what method to call. Remember the difference? In my example above, I deliberately wrote static at each myFunction. Those can be called object-less/target-less. You just need their name and you can call them from anywhere. To call them, a simple dumb pointer would be enough.

Now, delegates can do more. They can work on methods. But methods need to be invoked against an object..

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!

Ok, making a delegate to a static function in other class was easy - just had to say exactly what-function-from-what-class. Again just like calling, but without parenthesis.

But, if you try uncommenting the references to non-static methods, it will not compile. Looking at the GuineaPig.Well - that's obvious. It's not static, it needs to be called against OBJECT, not CLASS. For that very same reason, the delegate could not be created. Let's fix that:

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".

Note how classname was replaced with objectvariable during the creation of the delegate. The syntax is preserved: just like calling, but without parens. But, what's all the fuss about "methods" vs "functions"..

Delegates can store not only 'what method' to be called, but also what object to call them upon.

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

Now that is something you cannot do with plain function pointers. (Although with very smart function pointers you could.. but, let's leave that).

Note how the fact that "Well" was to be called on "pig#2" was stored inside the delegate object. The "myPiggie2" variable was irrelevant. I could nullify it. The delegate remembered both target and method.

System.Action is just one of the family. It's the simpliest, no params, no returns.. But there are many of them, they can get parameters (Action<string, int>) they can return values (Func<int>) or both (Func<string,int>). Yet, constantly speaking in terms of Func<int,float,string,int,int,bool,decimal> is somewhat ... obscure.

Ok. Let's finally get to the point of all this babbling. Sorry if you knew all of that, but I wanted to be clear.

A "delegate" is all about remembering "target" and "method". In fact, if you ever inspect a delegate in the debugger (or check what Intellisense says after the "dot"), you will see two properties, Target and Method. They are just what their names stand for.

Let's imagine you want to create your own type of a delegate. A type that would not be called Func<int,int,int,bool,bool,Zonk,string>, but rather, "MyStudentFilteringDelegate".

Now, whole point is, that in C# you cannot take &(address) of a function easily, and also you cannot overload the operator(). This results in you being unable to write your own delegate-like classes.

You cannot just write:

class MyStudentFilteringDelegate
{
     public object Target;
     public somethingstrange*  MethodPointer;

     // other code
}

because, even if you actually managed to follow that idea, somewhere at the end you would find that:

MyDelegate dd = new MyDelegate ( ... );
dd(); // is just impossible!!!

At least, in current C# version 4.5 or 5.

You just cannot overload the "call"/"invoke" operator, hence you would not be able to fully implement your own, custom-named, delegate type. You'd be stuck at Actions and Funcs for ever.

Now recall that red underline under the public void delegate xxx I asked you to temporarily forget.

public bool delegate MyStudentFilteringDelegate( Student stud );

This line does not create any delegate. This line defines a type of a delegate. It is perfectly the same as Func<Student,bool>, with custom name. *)

In fact, the compiler converts the line to:

public class MyStudentFilteringDelegate : some_framework_Delegate_class
{
    // object Target {get;} - inherited from base class
    // MethodInfo Method {get;} - inherited from base class, too
}

so that it is a class, and so that you can now create a delegate object:

var dd = new MyStudentFilteringDelegate ( ... ); // like normal class!
dd(); // ok!;

As the class is special, compiler-generated, it can break rules. It's 'call'/'invoke' operator is overloaded, so you can "call" the delegate as it were a method.

Please note that despite the strange notation:

public bool delegate MyStudentFilteringDelegate( Student stud );

the MyStudentFilteringDelegate is a class, just like Action or Func or String or WebClient are. The delegate keyword is just a marker for the compiler to know what transformation it should apply to that line to generate a proper "delegate type" (class).

Now, to actually answer your other question:

It is really irrelevant where you put the delegate type declaration. You may write public void delegate XYZ(...) anywhere you like. Just as you may place a class declaration just about anywhere.

You may place class declarations at default(no-namespace) scope, at some namespace, or inside a class. So, as the delegate-type is just a class, you may also delcare new delegate types at default(no-namespace) scope, at some namespace, or inside a class:

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();
    }
}

Note that I completely deliberately named them identically. That's no error. First are named ::global.Xc and ::global.Xd, the second pair is named WTF.Xc and WTF.Xd and the final pair is named WTF.Whatever.Xc and WTF.Whatever.Xd. Just like normal clases.

To decide where to place those declarations, use the same rules as you use for classes. Ie. if you place text-processing classes in namespace MyApp.Text.Parsing, then all the delegatetypes related to that text-processing should sit in that namespace too. But, even so, that's purely cosmetical and organizational. Place/define them at whatever scope it makes sense for you.

EDIT: *) actually, historically, it was all other way around. The delegate keyword and compiler trick is older than the Action and Func classes. At .Net 2.0, the Action/Func did not exist. The only way to create/use a delegate was to define your own new delegate type (or find/guess some suitable one somewhere deep in the system's namespaces). Keep in mind that every new delegate-type is a new class. Not convertible to any other class, not even similarly-looking. It was so frustratingly tiresome and hard to mantain, that at .Net 3.5 they finally included "general purpose generic delegate types" in the framework. From that point of time, Action/Func are increasingly often used, because even if they are harder to read, they are .. universal. System.Func<Student,bool> can be passed "anywhere", and you don't have a problem that 'bool delegate StudentFilter()from one library does not matchbool delegate StudentSelector()` from anoother one.

这篇关于如何使用正确的方法/了解delagates代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆