代码之家  ›  专栏  ›  技术社区  ›  Saif Khan

我还是找不到代表

  •  3
  • Saif Khan  · 技术社区  · 16 年前

    委托的使用是否有助于处理某些异步情况?我尝试了以下操作,但我的用户界面仍然挂起。你究竟什么时候使用代理人?

           Public Class Form1
        Private Delegate Sub testDelegate()
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As _
     System.EventArgs) Handles Button1.Click
    
            Dim d As testDelegate = New testDelegate(AddressOf Add)
            d.Invoke()
    
        End Sub
    
        Private Sub Add()
            For i As Integer = 0 To 10000
                TextBox1.Text = i + 1
            Next
        End Sub
    End Class
    
    7 回复  |  直到 16 年前
        1
  •  5
  •   Hans Passant    16 年前

    这有点讽刺,但事实上每个人最喜欢的答案(使用begininvoke)都不正确。委托目标方法将在线程池线程上执行。除了创建控件的线程外,不允许触摸其他线程上的控件,几乎总是程序的主线程。

    如果在调试器中使用.NET Framework 2.0及更高版本进行尝试,则循环将立即以非法操作异常终止。要纠正这个问题,您必须使用control.beginInvoke()。与委托的beginInvoke()方法btw完全不同的动物。

    讽刺的是,您的循环现在将向UI线程发送10000个委托调用请求。它将花费几秒钟来执行它们,而不是做任何真正的工作。就像发送文本框的绘制事件一样。或响应任何用户输入。事实上,你的境况比以前差得多。

    我怀疑这对解释代表们有很大帮助。也许你可以选择一个更好的例子,一个不尝试更新控件的例子。

        2
  •  7
  •   Matthew Savage    16 年前

    如joel所述-begininvoke()将异步执行委托-如果目标返回数据(使用endinvoke),则需要设置异步回调以检索返回值。

    以下链接是一篇关于使用委托进行异步编程的好文章: http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

    另外(这是C-抱歉)您可以使用lambda表达式处理回调:

    Action myAction = () => Console.WriteLine("This is an async call!");
    myAction.BeginInvoke(asyncResult => Console.WriteLine("Async Done!"), null);
    
        3
  •  2
  •   Joel Coehoorn    16 年前

    呼叫 .BeginInvoke() 而不是 .Invoke() .

        4
  •  2
  •   Joel Coehoorn    16 年前

    这是我发给同事的:

    基本上,委托可以用于回调、事件和异步处理。

    这里有一些示例代码,将每个示例复制并粘贴到新的命令行项目中。

    //Callbacks    
    //-------------------------------------------------------------------------------------------------------     
    delegate double DiscountRule(); // Declaration
    delegate string MessageFormat(); // Declaration
    
    class Message    
    {
        public string Instance() { return "You save {0:C}"; }
        public static string Class() { return "You are buying for {0:C}"; }
    
        public void Out(MessageFormat format, double d)
        {
            System.Console.WriteLine(format(), d);
    
        }
    }
    
    class Discount
    {
        public static double Apply(DiscountRule rule, double amount)
        {
            return rule() * amount; // Callback
        }
    
        public static double Maximum() { return 0.50; }
        public static double Average() { return 0.20; }
        public static double Minimum() { return 0.10; }
        public static double None() { return 0.00; }
    }
    
    class TestDelegate1
    {
        public static void Main()    
        {   
            DiscountRule[] rules = { // Instantiations  
                 Discount.None,
                 Discount.Minimum,    
                 Discount.Average,    
                 Discount.Maximum,    
                 };
    
            // Instantiation with a static method    
            MessageFormat format = Message.Class;
    
            double buy = 100.00;    
            Message msg = new Message();             
            msg.Out(format, buy); // Invocation     
    
            // Instantiation with an instance method    
            format = msg.Instance;
    
            foreach (DiscountRule r in rules)    
            {    
                double saving = Discount.Apply(r, buy); // Invocation    
                msg.Out(format, saving); // Invocation    
            }    
        }    
    }
    
    //--------------------------------------------------------------------------------------------------------    
    //Events:     
    
    //the delegate creates a new type    
    delegate void UpdateEventHandler();
    
    class Subject    
    {    
        private int data;
    
        public int GetData() { return data; }   
        public void SetData(int value) { data = value; Changed(); }    
        public event UpdateEventHandler Changed;    
    }
    
    class Observer    
    {    
        public Observer(Subject s) { subject = s; }    
        public Subject GetSubject() { return subject; }   
        private Subject subject;   
    }
    
    class HexObserver : Observer
    {    
        public HexObserver(Subject s)    
            : base(s)   
        {    
            s.Changed += Update;   
        }
    
        public void Update()    
        {   
            System.Console.Write("0x{0:X} ", GetSubject().GetData());    
        }    
    }
    
    class DecObserver : Observer    
    {
         public DecObserver(Subject s)    
            : base(s)    
        {    
            s.Changed += Update;   
        }
    
        public void Update()    
        {    
            System.Console.Write("{0} ", GetSubject().GetData());    
        }    
    }
    
    class TestEvent    
    {    
        public static void Main()    
        {   
            Subject s = new Subject();
    
            //assigns a Hex observer to object s (the constructor does the += assignment)    
            HexObserver ho = new HexObserver(s);
    
            //assigns a Decimal observer to object s    
            DecObserver co = new DecObserver(s);     
    
            for (int c; ; )    
            {    
                System.Console.Write("\nEnter a character" +    
                "(followed by a return, ctrl-C to exit): ");
    
                c = System.Console.Read();    
                s.SetData(c);    
                System.Console.Read(); // Two reads to get rid of the \r\n on PC.    
                System.Console.Read();   
            }    
        }    
    }
    

    .

    //--------------------------------------------------------------------------------------------------------  
    //Asynchronous processing (from http://msdn.microsoft.com/en-us/library/h80ttd5f(VS.71).aspx)         
    using System;    
    using System.Runtime.Remoting.Messaging;
    
    // Create an asynchronous delegate.    
    public delegate bool FactorizingAsyncDelegate (    
             int factorizableNum,     
             ref int primefactor1,    
             ref int primefactor2);
    
    // Create a class that factorizers the number.    
    public class PrimeFactorizer    
    {    
       public bool Factorize(
                    int factorizableNum,      
                    ref int primefactor1,    
                    ref int primefactor2)   
       {    
          primefactor1 = 1;    
          primefactor2 = factorizableNum;
    
          // Factorize using a low-tech approach.    
          for (int i=2;i<factorizableNum;i++)   
          {
             if (0 == (factorizableNum % i))    
             {
                primefactor1 = i;    
                primefactor2 = factorizableNum / i;    
                break;    
             }    
          }
    
          if (1 == primefactor1 )    
             return false;    
          else    
             return true   ;    
       }    
    }
    
    // Class that receives a callback when the results are available.    
    public class ProcessFactorizedNumber    
    {    
       private int _ulNumber;
    
       public ProcessFactorizedNumber(int number)   
       {    
          _ulNumber = number;   
       }
    
       // Note that the qualifier is one-way.    
       [OneWayAttribute()]    
       public void FactorizedResults(IAsyncResult ar)    
       {
          int factor1=0, factor2=0; 
    
          // Extract the delegate from the AsyncResult.      
          FactorizingAsyncDelegate fd = (FactorizingAsyncDelegate)((AsyncResult)ar).AsyncDelegate;
    
          // Obtain the result.    
          fd.EndInvoke(ref factor1, ref factor2, ar);
    
          // Output the results.    
          Console.WriteLine("On CallBack: Factors of {0} : {1} {2}",     
                       _ulNumber, factor1, factor2);    
       }    
    }
    
    // Class that shows variations of using Asynchronous    
    public class Simple    
    {    
       // The following demonstrates the Asynchronous Pattern using a callback.    
       public void FactorizeNumber1()    
       {
          // The following is the client code.    
          PrimeFactorizer pf = new PrimeFactorizer();    
          FactorizingAsyncDelegate fd = new FactorizingAsyncDelegate (pf.Factorize);
    
          int factorizableNum = 1000589023, temp=0; 
    
          // Create an instance of the class that is going   
          // to be called when the call completes.   
          ProcessFactorizedNumber fc = new ProcessFactorizedNumber(factorizableNum);
    
          // Define the AsyncCallback delegate.    
          AsyncCallback cb = new AsyncCallback(fc.FactorizedResults);
    
          // You can use any object as the state object.    
          Object state = new Object();
    
          // Asynchronously invoke the Factorize method on pf.   
          IAsyncResult ar = fd.BeginInvoke(
                               factorizableNum,     
                               ref temp, 
                               ref temp,     
                               cb,     
                               state);          
          //    
          // Do some other useful work.    
          //. . .    
       }    
    
       // The following demonstrates the Asynchronous Pattern using a BeginInvoke, followed by waiting with a time-out.    
       public void FactorizeNumber2()    
       {    
          // The following is the client code.    
          PrimeFactorizer pf = new PrimeFactorizer();    
          FactorizingAsyncDelegate fd = new FactorizingAsyncDelegate (pf.Factorize);
    
          int factorizableNum = 1000589023, temp=0; 
    
          // Create an instance of the class that is going     
          // to be called when the call completes.
          ProcessFactorizedNumber fc = new ProcessFactorizedNumber(factorizableNum);
    
          // Define the AsyncCallback delegate.    
          AsyncCallback cb =     
               new AsyncCallback(fc.FactorizedResults);
    
          // You can use any object as the state object.    
          Object state = new Object();
    
          // Asynchronously invoke the Factorize method on pf.   
          IAsyncResult ar = fd.BeginInvoke(   
                            factorizableNum,     
                            ref temp,     
                            ref temp,     
                            null,    
                            null); 
    
          ar.AsyncWaitHandle.WaitOne(10000, false);
    
          if (ar.IsCompleted)  
          {   
             int factor1=0, factor2=0;          
    
             // Obtain the result.    
             fd.EndInvoke(ref factor1, ref factor2, ar);    
    
             // Output the results.    
             Console.WriteLine("Sequential : Factors of {0} : {1} {2}", 
                           factorizableNum, factor1, factor2);   
          }    
       }
    
       public static void Main(String[] args)    
       {    
          Simple simple = new Simple();    
          simple.FactorizeNumber1();    
          simple.FactorizeNumber2();   
       }
    
        5
  •  2
  •   Christian C. Salvadó    16 年前

    我找到的最好的比喻来解释代表们,这是一个遗嘱或你的最后遗嘱。

    当然,这是你临死前写的一套说明,你把它放在一个安全的地方。你死后,你的律师会 执行 那些说明…

    委托通常在希望执行操作的代码不知道该操作应该是什么的足够详细信息时使用,您可以将其视为要在适当时间执行的一系列操作。

        6
  •  1
  •   FryGuy    16 年前

    在这种情况下,我可能不使用委托,因为您需要重新委托回UI线程来更新按钮。您可以在循环中使用application.doEvents使您的UI在更新时响应。

        7
  •  1
  •   Don Kirkby    16 年前

    正如Joel和Matthew提到的,BeginInvoke将异步执行委托。正如马修所说, this MSDN article 覆盖得很好。

    但是,如果您尝试在WinForms应用程序中进行一些后台工作,我建议您签出 background worker control . 对于使用WinForms事件驱动模型的开发人员来说,这将更加熟悉。