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

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

问题描述

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

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

我试图理解像Delegate这样的主题,目前我有几点,必须为我澄清
我在互联网上发现了很多不同的信息,描述如何使用它,但对于我来说,这个主题的理解有点复杂。

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)

所有描述我在下面显示

问题 - 我正确地理解了所有或者也许我错了 - 请澄清一下。

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

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

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.

但是也许有一些推荐/要求不仅适用于控制台应用程序,还适用于WinForms,WPF等。

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.

编辑

namespace SimpleCSharpApp
{
   delegate void myDelagate ();
}


推荐答案

Ho-ho ..你有一些事情搞砸了在代理声明下,我看到VS的屏幕截图显示为红色下划线,我并没有完全了解你正在尝试的问题。

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.

首先, code> public void delegate zczcxxzc 一段时间。有点特别首先,让我们看看一些标准的*)代表。

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.

两个最基本的是:


  • System.Action

  • System.Func / li>
  • 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.

对于初学者,我们限制为裸,无参数, System.Action

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"

就像int持有一个数字,string - 文本, 代表持有关于可被呼叫的信息,或者使用一些术语可调用的东西。

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

首先,我创建一个记住myFunction1的Action类型的委托。然后我调用/调用该委托 - 它会导致被调用的函数。

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.

然后,我创建一个Action类型的委托记得myFunction2。然后我调用/调用该委托 - 它会导致被调用的函数。

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.

最后,我创建一个Action类型的委托记得myFunction3。然后我调用/调用该委托 - 它导致所记住的函数被调用,没有任何反应 - 但是仅仅因为目标函数没有任何操作。

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.

请注意,我故意说创建代表。每次执行新Action 时,将创建一个新的委托。 代理只是一个对象,如Stringfoo或float [] {1.2,4.5}。

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

此外,请注意,创建委托使用的完整语法这里是 new Action(...)。就像创建任何对象 - new + typename +构造参数一样。还有一个迹象表明,一个代表只是一个对象。

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.

另外要注意的是我没有写 new Action(myFunction1() )。我不想CALL的方法并获得其结果,并将该结果提交给Action的构造函数。我写了 new Action(myFunction1)。我把函数本身赋给构造函数。

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.

但是,那么什么是Action? System.Action是一个类。像String或Socket或WebClient。这里没什么特别的所以我们有一个类,其对象可以记住什么是功能 - 应该被称为。很酷。

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.

因此,一些比较代理到函数指针。但这不完全正确。函数指针可以记住调用什么函数。代表们可以记住要调用的方法。记得差异吗在我上面的例子中,我在每个 myFunction 中故意写了 static 。那些可以被称为无对象/无目标的。你只需要他们的名字,你可以从任何地方打电话给他们。要调用它们,一个简单的哑指针就够了。

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.

但是,如果您尝试取消注释非静态方法的引用,则不会编译。看看 GuineaPig.Well - 这很明显。它不是静态的,需要调用OBJECT,而不是CLASS。由于同样的原因,无法创建代表。我们来解决一下:

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

注意在委托创建过程中,如何使用objectvariable替换类名。语法被保留:就像调用一样,但没有括号。但是,对于方法与函数有什么关系呢?

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

请注意猪2号被存储在委托对象中。 myPiggie2变量是无关紧要的。我可以否认它。代表们记住目标和方法。

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只是家庭之一。它是最简单的,没有参数,没有返回。但是有很多,他们可以获取参数( Action< string,int> ),他们可以返回值( Func< int> )或两者( Func< string,int> )。然而,在 Func< int,float,string,int,int,bool,decimal> 方面不断地说是有点模糊。

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.

代表是关于记住目标和方法。实际上,如果您检查调试器中的代理(或检查Intellisense在点之后所说的),您将看到两个属性Target和Method。他们只是他们的名字所代表的。

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.

让我们假设你想创建一个自己的代理类型。一种不会被称为 Func< int,int,int,bool,bool,Zonk,string> 的类型,而是MyStudentFilteringDelegate。

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

现在,整体而言,在C#中,您不能轻松地使用 c& (地址)功能 ,而且你不能重载operator()。这导致您无法编写自己的代理类。

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.

您不能写:

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!!!

至少在当前C#版本4.5或5中。

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

你不能重载call/invoke运算符,因此你将无法完全实现自己的定制命名的委托类型。现在记得在下的红色下划线public void delegate xxx

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.

>我请你暂时忘记。

public bool delegate MyStudentFilteringDelegate( Student stud );

此行不创建任何委托。此行定义了一个代表类型。与 Func< Student,bool> 和自定义名称完全相同。 *)

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!;

由于类是特殊的,编译器生成的,它可以打破规则。它是'call'/'invoke'运算符被重载,所以你可以调用委托,因为它是一种方法。

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.

请注意,尽管有奇怪的符号: / p>

Please note that despite the strange notation:

public bool delegate MyStudentFilteringDelegate( Student stud );

MyStudentFilteringDelegate 是一个,就像Action或Func或String或WebClient一样。 关键字只是编译器知道应用于该行的转换,以生成适当的委托类型(class)。

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:

真的 em>委托类型声明。你可以在任何你喜欢的地方写 public void delegate XYZ(...)就像你可以在任何地方放置一个类声明

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

请注意,我完全故意命名他们。这没有错误。首先被命名为 :: global.Xc :: global.Xd ,第二个对命名为$ code> WTF.Xc 和 WTF.Xd ,最后一个对命名为 WTF.Whatever.Xc WTF.Whatever.Xd 。就像正常的Clases一样。

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.

要决定放置这些声明的位置,请使用与您用于类的规则相同的规则。也就是如果您在命名空间 MyApp.Text.Parsing 中放置文本处理类,则与该文本处理相关的所有代理类都应该位于该命名空间中。但是,即使如此,这纯粹是美化和组织的。在任何适用范围的地方/定义它们。

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.

编辑:
*)实际上,在历史上,这是其他方式。与$和Func类相比,委托关键字和编译器技巧较旧。在.Net 2.0中,Action / Func不存在。创建/使用委托的唯一方法是定义您自己的新委托类型(或者在系统命名空间深处查找/猜出一些合适的类型)。请记住,每个新的委托类型都是一个新类。不能转换成任何其他类,甚至不是类似的。在.NET 3.5中,他们终于在框架中包含了通用通用代理类型,令人沮丧,令人沮丧。从那个时候起,Action / Func越来越多地被使用,因为即使它们更难阅读,它们是通用的。 System.Func< Student,bool> 可以在任何地方传递,而且您没有任何问题bool delegate StudentFilter()一个库不匹配 bool delegate StudentSelector()`from anoother one。

*) 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.

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

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