Noobie代表基础知识C#

时间:2012-02-21 20:05:39

标签: c# delegates

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

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()一样......

有人可以解释一下吗?非常感谢!

5 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:3)

  

我不明白为什么只需要实现一个getListStrings()并自己遍历字符串,执行你需要做的事情就好了,为什么需要这样做,就像它是一个委托一样。

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

通过示例更容易理解 - 要查看有用的方法和原因的一个很好的示例,请查看LINQ to Objects。

假设您要查看有多少字符串超过4个字符 - Enumerable.Count方法有一个带有委托的重载 - 可以使用Func<T,bool>谓词。这允许您指定任何操作并计算元素,即:

List<string> listOfStrings = GetListOfStrings();

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

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

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

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

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

答案 2 :(得分:1)

在插图中使用代理可以更改方法的实现。

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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并过滤集合)或者像我这样的回调/事件上面已经证明了这一点。