C#代表在现实世界中的使用


16

我认为我在概念上理解C#代表,但是,我一直在努力寻找一个有用的现实示例。您能否提供一些答案,详细说明在实际应用程序中如何使用C#委托以及它们使您能够解决哪些问题。


2
.NET框架中的几乎每个类都公开了一些事件集,所以您就可以开始了。这只是封装某些工作单元的一种方法。例如,假设您正在C中实现一个通用的二叉树结构。那么,对树进行排序的唯一方法是将一个知道如何进行排序的函数指针作为参数。
Ed S.

Answers:


16

GUI代码使用委托来处理事件,例如按钮单击,窗口移动。使用委托可以使您确实在事件发生时调用一个函数。例如,将一个将数据保存功能链接到界面上的“保存”按钮。单击该按钮后,将其设置为执行保存数据的功能。这在GUI编程中很有用,因为您的整个程序可能正在等待用户执行某项操作,而您无法知道他们将首先执行的操作。使用委托可以将程序的功能连接到UI,使用户可以按照自己想要的任何方式进行操作。


2
++您是对的,但我仍然讨厌它:-)所以很久以前,我想到了这个
Mike Dunlavey

12

Linq在各处使用Func<T>Action<T>委托作为参数。

这些允许您将lambda表达式用作参数,并定义要作为参数列表一部分执行的操作。


12

几乎所有使用观察者模式的东西都可能实现委托。

阅读说明,您可能会想象一些使用它们的场景。GUI事件处理是一个常见的示例。


+1,策略模式实际上是代表发光的地方,即,您有一些类,其中某些方法可以执行某些操作,但是您希望这些东西可以互换并且没有直接的依赖关系,因此请使用ergo委托。请注意,事件某种程度上满足了与委托相同的需求,不同之处在于,当您需要对某些返回值做出反应时,您可以使用委托,而您只需触发事件,一切都会发生。
霍姆德2011年

9

委托在异步编程中很有用。

您有一个异步填充并具有回调的类。您可以在回调时调用委托方法-您的类实现将执行委托方法中描述的逻辑。


9

代表作为解决中间模式中漏洞的方法特别有用。本质上,在很多情况下,您都希望在一组通用指令中包装一组独特的指令。如果唯一位之前和之后的指令需要共享状态,则特别困难。使用委托,您可以仅将委托传递给函数。该函数执行前一位,执行委托,然后执行后一位。


5

在非OOP语言(例如Fortran和C)的“旧时代”中,能够让子例程接收作为函数指针的参数非常有用。例如,qsort功能与用户提供的比较功能一起使用。有许多子例程可用于求解常微分方程或用于优化函数,它们均以函数指针作为参数。

在窗口系统中,各种回调都遵循相同的模式。

在Lisp中,即使在早期,也有一种称为“函数参数”或FUNARG的东西,它不仅是一个函数,而且还包含一个存储上下文,可以在其中记忆并与外界交互。

OOP语言中也存在相同的需求,除了传递函数的地址时,还必须传递函数的对象的地址。这是您必须通过的两件事。因此,委托就是这样,并且允许仍然使用该旧模式。


3

这是一个简单的示例,显示了在遵循DRY原理创建简单代码时委托有多么有用。它还允许您将代码保持在非常接近需要的地方。

Action<Button, Action<Button>> prepareButton = 
    (btn, nxt) => { 
        btn.Height = 32;
        btn.Width= 64;
        nxt(btn);
    };

prepareButton(myBtn1, btn => btn.Text = "A");
prepareButton(myBtn2, btn => btn.Text = "B");
prepareButton(myBtn3, btn => btn.Text = "C");

这是代表提供的优势的真实示例。

protected override void PageInitialize()
{
    const string selectCodeFormat = "javascript:selectCode('{0}', '{1}');";
    const string onClick = "return toggleElement(this);";

    Func<HtmlGenericControl> getElement = null;
    Action<HtmlGenericControl> setElement = null, addChild = null;
    HtmlGenericControl level1Element = null, level2Element = null, level3Element = null, level4Element = null;
    string className = null, code = null, description = null;           

    using (var records = Core.Database.ExecuteRecords("code.SocCodeTree"))
    {
        while (records.Read())
        {
            code = records.GetString("Code");
            description = records.GetString("Description"); 

            if (records.GetString("Level4") != "")
            {
                className = "Level4";
                setElement = e => level4Element = e;
                getElement = () => level4Element;
                addChild = e => level3Element.Controls.Add(e);
            }
            else if (records.GetString("Level3") != "")
            {
                className = "Level3";
                setElement = e => level3Element = e;
                getElement = () => level3Element;
                addChild = e => level2Element.Controls.Add(e);
            }
            else if (records.GetString("Level2") != "")
            {
                className = "Level2";
                setElement = e => level2Element = e;
                getElement = () => level2Element;
                addChild = e => level1Element.Controls.Add(e);
            }
            else
            {
                className = "Level1";
                setElement = e => level1Element = e;
                getElement = () => level1Element;
                addChild = e => Root.Controls.Add(e);
            }

            var child = new HtmlGenericControl("li");
            child.Attributes["class"] = className;
            var span = new HtmlGenericControl("span") { 
                InnerText = code + " - " + description + " - " 
            };
            span.Attributes["onclick"] = onClick;
            child.Controls.Add(span);
            var a = new HtmlAnchor() { 
                InnerText = "Select", 
                HRef = string.Format(selectCodeFormat, code, description) 
            };
            child.Controls.Add(a);
            setElement(new HtmlGenericControl("ul"));
            child.Controls.Add(getElement());
            addChild(child);    
        }
    }
}

2

我与委托的第一次接触是通过从我的网站下载文件来检查程序更新(Windows窗体C#3.5),但是为了避免更新检查锁定整个程序,我使用了委托和线程来异步进行更新。


1

我已经看到了有效使用委托的Strategy模式的有趣实现。(即该策略是代表)

我正在查看的是路径查找,其中查找路径的算法是可以在运行时(重新)分配给它的委托,以便可以使用不同的算法(BFS与A *等)。


1

许多经典的GoF模式都可以使用委托来实现:例如,命令模式,访问者模式,策略模式,工厂模式和观察者模式通常可以通过简单的委托来实现。有时,类会更好(例如,当命令需要名称或需要序列化策略对象时),但是在大多数情况下,使用Action<...>Func<...>比创建专用的单方法界面更为优雅。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.