3

デリゲートの使用は、いくつかの非同期ケースに役立つのではないでしょうか? 次のことを試しましたが、UI がまだハングします。一体いつデリゲートを使用しますか?

       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
4

7 に答える 7

7

Joelが述べたように、BeginInvoke()はデリゲートを非同期的に実行します。ターゲットがデータを返す場合(EndInvokeを使用)、戻り値を取得するために非同期コールバックを設定する必要があります。

次のリンクは、非同期プログラミングにDelegatesを使用するための優れた記事です:http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

また(これはC#にあります-申し訳ありません)ラムダ式を使用してコールバックを処理できます:

Action myAction = () => Console.WriteLine("This is an async call!");
myAction.BeginInvoke(asyncResult => Console.WriteLine("Async Done!"), null);
于 2008-12-30T00:46:15.027 に答える
5

皮肉なことですが、みんなの好きな答え(BeginInvokeを使用)は実際には正しくありません。デリゲートターゲットメソッドは、スレッドプールスレッドで実行されます。コントロールを作成したスレッド以外のスレッド(ほとんどの場合、プログラムのメインスレッド)のコントロールに触れることはできません。

デバッガーで.NETFrameworkバージョン2.0以降を使用して試してみると、ループはIllegalOperationExceptionですぐに終了します。これを修正するには、Control.BeginInvoke()を使用する必要があります。デリゲートのBeginInvoke()メソッドとはまったく異なる動物です。

皮肉なことに、ループは10,000個のデリゲート呼び出し要求をUIスレッドにディスパッチします。実際の作業に取り掛かることなく、それらを実行するのに数秒かかります。TextBoxのPaintイベントをディスパッチするようなものです。または、ユーザー入力に応答します。あなたは実際、以前よりもはるかに悪化しています。

これが代表者の説明に大いに役立つとは思えません。たぶん、コントロールを更新しようとしない、より良い例を選ぶことができます。

于 2008-12-30T05:02:18.143 に答える
2

これが私が同僚に送ったものです:

基本的に、デリゲートは、コールバック、イベント、および非同期処理に使用できます。

ここにいくつかのサンプルコードがあります。各例をコピーして新しいコマンドラインプロジェクトに貼り付けてください。

//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();   
   }
于 2008-12-30T00:39:08.190 に答える
2

.BeginInvoke()ではなく呼び出し.Invoke()ます。

于 2008-12-30T00:41:36.080 に答える
2

代表者を説明するために私が見つけた最高の例えは、それが遺言またはあなたの最後の意志です。

もちろん、死ぬ前に書く一連の指示であり、安全な場所に置いておきます。そして、あなたの死後、あなたの弁護士はそれらの指示を実行します...

デリゲートは主に、アクションを実行したいコードがそのアクションの詳細を十分に知らない場合に使用されます。適切なタイミングで実行される一連のアクションとして表示できます。

于 2008-12-30T01:03:05.630 に答える
1

この場合、ボタンを更新するためにUIスレッドに再度デリゲートする必要があるため、デリゲートを使用しない可能性があります。ループ内でApplication.DoEventsを使用して、更新中にUIをレスポンシブにすることができます。

于 2008-12-30T00:48:28.813 に答える
1

Joel と Matthew が言及しているように、BeginInvoke はデリゲートを非同期的に実行します。Matthew が言うように、この MSDN 記事はそれをうまくカバーしています。

ただし、WinForms アプリケーションでバックグラウンド作業を行う場合は、バックグラウンド ワーカー コントロールを確認することをお勧めします。WinForms のイベント ドリブン モデルに慣れている開発者にとっては、より馴染み深いものになるでしょう。

于 2008-12-30T01:20:51.977 に答える