102

您在 C# 中对委托的使用是什么?

4

20 回答 20

100

现在我们在 C# 中有 lambda 表达式和匿名方法,我更多地使用委托。在 C# 1 中,您总是必须有一个单独的方法来实现逻辑,使用委托通常没有意义。这些天我使用代表:

  • 事件处理程序(用于 GUI 等)
  • 启动线程
  • 回调(例如异步 API)
  • LINQ 和类似(List.Find 等)
  • 我想在其他任何地方有效地应用带有一些专门逻辑的“模板”代码(委托提供专门化的地方)
于 2008-10-10T13:07:45.790 回答
29

代表对许多用途都非常有用。

一个这样的目的是使用它们来过滤数据序列。在这种情况下,您将使用一个谓词委托,它接受一个参数并根据委托本身的实现返回真或假。

这是一个愚蠢的例子——我相信你可以从中推断出更有用的东西:

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<String> names = new List<String>
        {
            "Nicole Hare",
            "Michael Hare",
            "Joe Hare",
            "Sammy Hare",
            "George Washington",
        };

        // Here I am passing "inMyFamily" to the "Where" extension method
        // on my List<String>.  The C# compiler automatically creates 
        // a delegate instance for me.
        IEnumerable<String> myFamily = names.Where(inMyFamily);

        foreach (String name in myFamily)
            Console.WriteLine(name);
    }

    static Boolean inMyFamily(String name)
    {
        return name.EndsWith("Hare");
    }
}
于 2009-07-31T19:00:18.457 回答
15

找到另一个有趣的答案:

一位同事刚刚问了我这个问题——.NET 中的代表有什么意义?我的回答很简短,而且他没有在网上找到:延迟执行方法。

资料来源:LosTechies

就像 LINQ 正在做的那样。

于 2008-10-16T18:12:31.910 回答
13

委托通常可以用一种方法代替接口,一个常见的例子就是观察者模式。在其他语言中,如果您想收到发生某事的通知,您可以定义如下内容:

class IObserver{ void Notify(...); }

在 C# 中,这更常使用事件来表达,其中处理程序是委托,例如:

myObject.SomeEvent += delegate{ Console.WriteLine("..."); };

如果您必须将谓词传递给函数,例如从列表中选择一组项目时,另一个使用委托的好地方:

myList.Where(i => i > 10);

上面是 lambda 语法的一个例子,它也可以写成如下:

myList.Where(delegate(int i){ return i > 10; });

使用委托的另一个有用的地方是注册工厂函数,例如:

myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);

我希望这有帮助!

于 2009-07-31T19:04:55.967 回答
12

您可以使用委托来声明函数类型的变量和参数。

例子

考虑“资源借用”模式。您希望控制资源的创建和清理,同时允许客户端代码在两者之间“借用”资源。

这声明了一个委托类型。

public delegate void DataReaderUser( System.Data.IDataReader dataReader );

任何匹配此签名的方法都可用于实例化此类型的委托。在 C# 2.0 中,这可以隐式地完成,只需使用方法的名称,也可以使用匿名方法。

此方法使用类型作为参数。注意委托的调用。

public class DataProvider
{
    protected string _connectionString;

    public DataProvider( string psConnectionString )
    {
        _connectionString = psConnectionString;
    }

    public void UseReader( string psSELECT, DataReaderUser readerUser )
    {
        using ( SqlConnection connection = new SqlConnection( _connectionString ) )
        try
        {
            SqlCommand command = new SqlCommand( psSELECT, connection );
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();

            while ( reader.Read() )
                readerUser( reader );  // the delegate is invoked
        }
        catch ( System.Exception ex )
        {
            // handle exception
            throw ex;
        }
    }
}

可以使用匿名方法调用该函数,如下所示。请注意,匿名方法可以使用在其外部声明的变量。这非常方便(尽管这个例子有点做作)。

string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";

DataProvider.UseReader( sQuery,
    delegate( System.Data.IDataReader reader )
    {
        Console.WriteLine( sTableName + "." + reader[0] );
    } );
于 2008-10-10T13:27:07.217 回答
10

我很晚才加入,但我今天很难弄清楚代表的目的,并编写了两个简单的程序,它们给出的输出相同,我认为很好地解释了它们的目的。

NoDelegates.cs

using System;

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Test.checkInt(1);
        Test.checkMax(1);
        Test.checkMin(1);

        Test.checkInt(10);
        Test.checkMax(10);
        Test.checkMin(10);

        Test.checkInt(20);
        Test.checkMax(20);
        Test.checkMin(20);

        Test.checkInt(30);
        Test.checkMax(30);
        Test.checkMin(30);

        Test.checkInt(254);
        Test.checkMax(254);
        Test.checkMin(254);

        Test.checkInt(255);
        Test.checkMax(255);
        Test.checkMin(255);

        Test.checkInt(256);
        Test.checkMax(256);
        Test.checkMin(256);
    }
}

代表.cs

using System;

public delegate void Valid(int a);

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Valid v1 = new Valid(Test.checkInt);
        v1 += new Valid(Test.checkMax);
        v1 += new Valid(Test.checkMin);
        v1(1);
        v1(10);
        v1(20);
        v1(30);
        v1(254);
        v1(255);
        v1(256);
    }
}
于 2012-10-05T22:01:00.420 回答
5

稍微不同的用途是加速反射;即不是每次都使用反射,您可以使用Delegate.CreateDelegate为方法(a)创建一个(类型化的)委托MethodInfo,然后调用该委托。由于检查已经完成,因此每次调用都会更快。

使用Expression,您也可以执行相同的操作来动态创建代码 - 例如,您可以轻松地Expression为运行时选择的类型创建一个表示 + 运算符(为泛型提供运算符支持,该语言不提供) ; 你可以编译Expression一个类型化的委托 - 工作完成。

于 2008-10-10T13:19:27.730 回答
5

每当您使用事件时都会使用委托 - 这就是它们的工作机制。

此外,委托对于诸如使用 LINQ 查询之类的事情非常有用。例如,许多 LINQ 查询采用Func<T,TResult>可用于过滤的委托(通常)。

于 2009-07-31T19:01:07.143 回答
4

为事件订阅事件处理程序

于 2008-10-10T13:05:11.800 回答
2

一个例子可能是在这里看到的。您有一种方法来处理满足某些要求的对象。但是,您希望能够以多种方式处理对象。不必创建单独的方法,您可以简单地将处理对象的匹配方法分配给委托,并将委托传递给选择对象的方法。这样,您可以将不同的方法分配给一个选择器方法。我试图让这很容易理解。

于 2012-10-10T21:33:06.737 回答
1

我使用委托与线程进行通信。

例如,我可能有一个下载文件的 win forms 应用程序。该应用程序启动一个工作线程来进行下载(这可以防止 GUI 锁定)。工作线程使用委托将状态消息(例如下载进度)发送回主程序,以便 GUI 可以更新状态栏。

于 2008-10-21T03:41:02.230 回答
0
  1. 对于事件处理程序

  2. 在方法参数中传递方法

于 2008-10-10T13:07:52.247 回答
0

第一行的用法是替换 Observer/Observable(事件)模式。第二个,一个漂亮优雅的策略模式版本。可以收集各种其他用法,尽管比我认为的前两个更深奥。

于 2008-10-10T13:08:03.323 回答
0

事件,其他anynch操作

于 2008-10-10T13:08:13.463 回答
0

任何时候你想封装行为,但以统一的方式调用它。事件处理程序、回调函数等。您可以使用接口和强制转换来完成类似的事情,但有时,行为不一定与类型对象相关联。有时你只是有你需要封装的行为。

于 2008-10-10T13:09:56.657 回答
0

懒惰的参数初始化!除了所有先前的答案(策略模式、观察者模式等)之外,委托还允许您处理参数的延迟初始化。例如,假设您有一个函数 Download(),它需要相当多的时间并返回某个 DownloadedObject。此对象由存储根据特定条件消耗。通常,您会:

storage.Store(conditions, Download(item))

但是,使用委托(更准确地说,lambdas),您可以通过更改 store 的签名来执行以下操作,以便它接收 Condition 和 Func<Item,DownloadedObject> 并像这样使用它:

storage.Store(conditions, (item) => Download(item))

因此,存储只会在必要时评估委托,根据条件执行下载。

于 2008-10-10T13:18:12.163 回答
0

代表的使用

  1. 事件处理
  2. 多铸件
于 2008-10-10T13:37:41.673 回答
0

In Array.Sort(T[] array,Comparison comparison)、List.Sort(Comparison comparison)等中的比较参数

于 2008-10-11T15:12:19.373 回答
0

据我所知,委托可以转换为函数指针。当与采用函数指针的本机代码进行互操作时,这使得生活变得更加容易,因为它们可以有效地面向对象,即使最初的程序员没有为此做任何准备。

于 2010-08-25T16:25:02.717 回答
0

委托用于通过引用调用方法。例如:

  delegate void del_(int no1,int no2);
class Math
{
   public static void add(int x,int y)
   {
     Console.WriteLine(x+y);
   }
   public static void sub(int x,int y)
   {
     Console.WriteLine(x-y);
   }
}



    class Program
    {
        static void Main(string[] args)
        {
            del_ d1 = new del_(Math.add);
            d1(10, 20);
            del_ d2 = new del_(Math.sub);
            d2(20, 10);
            Console.ReadKey();
        }
    }
于 2012-02-07T04:43:52.853 回答