【问题标题】:Noobie Delegate Fundamentals C#Noobie 代表基础 C#
【发布时间】:2012-02-21 20:05:39
【问题描述】:

我不认为我理解委托方法的意义。我见过的所有例子都是这样的:

class DelegateClass
{
    private List<string> ListString = new List<string>;
    delegate void DoSomethingToStringsDelegate(string s);

    public base()
    {
         ListString.Add("string"); ....
    }

    void ProcessStrings(DoSomethingToStringsDelegate dstsd)
    {
        foreach(string s in ListString)
            dstsd(s);
    }
}

class AClass
{
    ...
    void UseDelegateMethod(...)
    {
        DelegateClass ds = new DelegateClass();
        ds.ProcessStrings(new DoSomethingToStringsDelegate(PrintStrings);
    }
    void PrintStrings(string s)
    {
        System.out.Write(s);
    }
}

当你可以简单地实现一个 getListStrings() 并自己遍历字符串,做你需要做的事情时,我不明白为什么需要这样做,就好像它是一个委托一样。

foreach( string s in ds.ggetListStrings() )
    System.out.Write(s);

私人会员的理由没有意义,因为我可以这样做:

global List<Strings> myListStrings = new List<Strings>();
ds.ProcessStrings(new DoSomethingToStringsDelegate(GetStrings);

void GetStrings(string s)
{
    myListStrings.Add(s);
}

...现在我有了相同的列表,就像 getListStrings() 会做的那样...。

谁能解释一下?非常感谢!

【问题讨论】:

  • 那个例子看起来……很复杂。我可能不会这样写,尽管我需要知道更大的上下文;-) 但是,委托 (delegate/Action/Func) 的“要点”是它可以在不同的上下文中调用:例如作为回调。相反,请考虑 Regex.Replace(string,string,MatchEvaluator),它显示了一个委托 (MatchEvaluator) 以一种非常有用的方式使用。 (曾经尝试在 Java 中进行类似的正则表达式替换吗?这不好玩。)
  • 再一次,难道你不能这样做... if(MatchEvaluator) Regex.Replace(string, string)?

标签: c# delegates


【解决方案1】:

delegate 很有用,因为它实际上充当任何将string 作为参数并返回void 的方法的占位符。

如果你熟悉 C,它类似于函数指针的工作方式。取而代之的是,您可以传递任何匹配签名和返回类型的方法。

例如,假设我想实现一个对一组对象进行排序的方法。除了对象列表之外,我还可以传递一个指示如何进行排序的委托。由于可以传递与委托匹配的任何方法,因此如果我想减少或增加排序,我可以在不同的方法之间动态切换:

 delegate int comparisonDelegate(int p1, int p2);

 void SortArray(int[] array, comparisonDelegate cmp)
 {
      // determine order according to cmp
 }

 int CompareDecreasing(int p1, int p2)
 {
     if(p1 > p2) return -1;
     if(p1 < p2) return 1;
     return 0;
 }

 int CompareIncreasing(int p1, int p2)
 {
     if(p1 > p2) return 1;
     if(p1 < p2) return -1;
     return 0;
 }

现在我可以打电话给SortArray

 SortArray(array, new comparisonDelegate(compareDecreasing));
 SortArray(array, new comparisonDelegate(compareIncreasing));

【讨论】:

  • 您的示例没有定义任何 compareIncreasing 方法,而是有两个相同的 compareDecreasing 签名... ;)
【解决方案2】:

当您可以简单地实现一个 getListStrings() 并自己遍历字符串,做您需要做的事情时,我不明白为什么需要这样做,就好像它是一个委托一样。

这里的目标是创建一个对集合起作用的函数,但可以执行任何操作。

这更容易通过示例来掌握 - 要查看如何以及为什么有用的一个很好的示例,请查看 LINQ to Objects。

假设您想查看有多少字符串大于 4 个字符 - Enumerable.Count 方法有一个接受委托的重载 - 一个可以使用的 Func&lt;T,bool&gt; 谓词。这使您可以指定 任何 操作并计算元素,即:

List<string> listOfStrings = GetListOfStrings();

int countOfStringsGreaterThanFourChars = listOfStrings.Count(s => s.Length > 4);

在这里,我们传递了一个委托(通过 lambda 表达式创建),它为我们提供了我们的标准。通过拥有一个接受委托的Count 方法,它适用于任何条件,因此我们不必在每次需要不同条件时都重新实现它。

假设我们想查看有多少以“E”开头的字符串,我们可以使用:

int countOfStringsStartingWithE = listOfStrings.Count(s => s.StartsWith("E"));

同样,我们只需要编写与我们的特定需求相关的代码,而不是复制循环遍历我们的集合和计算项目所需的所有样板代码...

【讨论】:

    【解决方案3】:

    在您的插图中使用委托允许您更改方法的实现。

    比较器方法是一个更好的例子。我不会进入IComparer 接口,但我只想说,使用委托,您可以通过将委托传递给比较函数来修改排序方法的行为。

    http://msdn.microsoft.com/en-us/library/system.collections.icomparer.aspx

    【讨论】:

      【解决方案4】:

      一方面,它允许您使用相同的方法签名注入不同的行为。在一种情况下,您可能只想简单地添加到您的列表中。在另一种情况下,您可能想要添加到列表并写入日志文件,或者您可能想要在 DoSomethingToStringsDelegate 中执行的任何其他操作。

      【讨论】:

        【解决方案5】:

        从事件的角度来考虑它。假设您有一个类对项目列表进行一些处理,并且对于每个项目,使用您的类的人可能希望收到一个项目已处理的通知(可能更新进度条,或更新系统的其他部分, 任何)。让我们先把委托放在一边,让我们看看如何使用接口来实现它:

        public class MyClassThatDoesSomething
        {
           private List<string> list = new List<string>();
           public void ProcessList()
           {
              foreach(var item in list)
              {
                 ProcessItem(item);
                 //how do we notify someone here??
              }
           }
        
           private void ProcessItem(string item){}
        }
        

        现在说有人在消费这个类:

        var mc = new MyClassThatDoesSomething();
        mc.ProcessList(); //how do I know when each one has been processed?
        

        那么解决这个问题,我们来创建一个接口:

        public interface IItemProcessed
        {
           void ItemProcessed(string item);
        }
        

        我们现在可以重构我们原来的类:

        public class MyClassThatDoesSomething
        {
           private List<string> list = new List<string>();
           public void ProcessList()
           {
              foreach(var item in list)
              {
                 ProcessItem(item);
                 //how do we notify someone here??
                 if(this.Listener != null)
                 {
                     this.Listener.ItemProcessed(item);
                 }
              }
           }
        
           private void ProcessItem(string item){}
        
           public IItemProcessed Listener {get;set;}
        }
        

        你班级的消费者现在可以这样做了:

        public class ProcessListener : IItemProcessed
        {
           public void ItemProcessed(string item)
           {
              Console.WriteLine(item);
              //update progress bar, whatever
           }
        }
        
        var mc = new MyClassThatDoesSomething();
        mc.Listener = new ProcessListener();
        mc.ProcessList(); 
        

        现在您了解了这一点,您可以将委托视为迷你接口,然后您可以将原始类更改为:

        public class MyClassThatDoesSomething
        {
           private List<string> list = new List<string>();
           public void ProcessList()
           {
              foreach(var item in list)
              {
                 ProcessItem(item);
                 //how do we notify someone here??
                 if(this.Callback != null)
                 {
                     this.Callback(item);
                 }
              }
           }
        
           private void ProcessItem(string item){}
        
           public Action<string> Callback {get;set;}
        }
        

        和消费者:

        var mc = new MyClassThatDoesSomething();
        mc.Listener = s =>
        {
           Console.WriteLine(s);
           //update progress bar, whatever
        }
        mc.ProcessList(); 
        

        总而言之,您可以将委托视为一种向外部人员提供简单“挂钩”到您的代码中的方式,以便让他们提供小块逻辑(想想 Linq 和过滤集合)或像我这样的回调/事件'上面已经证明了。

        【讨论】:

          猜你喜欢
          • 2018-03-26
          • 1970-01-01
          • 1970-01-01
          • 2018-12-09
          • 2018-07-11
          • 2021-10-02
          • 2010-11-13
          • 2016-04-07
          • 1970-01-01
          相关资源
          最近更新 更多