none
VB.net非同期処理でIntegerを返す関数が作成できない RRS feed

  • Question


  •     Private 【Async】Function func1() As Integer

            Dim r As Integer

            'rを操作するコードをここに書く

            '↓こうしないとMe.ComboBox1.Textが描き変わらない
            Await Task.Run(Sub() System.Threading.Thread.Sleep(50))

            'WPFコントロールの描画
            Me.ComboBox1.Text = ""

            Return r

        End Function

    上の様に、Integerの値を返す関数を作りたいのですが、【Async】を記述すると関数の宣言の行末が As Task(Of Integer) に書き変わってしまいます。
    戻り値はIntegerでなくてはならないので、解決策を教えて下さい。

    Await Task.Run(Sub() System.Threading.Thread.Sleep(50)) は外すことができませんので、Asyncを宣言しないとエラーになりコンパイルできません。

    よろしくお願い致します。
    Friday, October 4, 2019 7:09 AM

Answers

All replies

  • 何が起こっているのか分かりませんので、ハズレのような気もしますが・・・

    > こうしないとMe.ComboBox1.Textが描き変わらない

    代わりに Windows Forms アプリの Application.DoEvents と同様な機能を入れてみたらどうなりますか?

    具体的には、以下のドキュメントのサンプルコードを見てください。

    DispatcherFrame Class
    https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.threading.dispatcherframe?redirectedfrom=MSDN

    ハズレだったらすみません。

    Friday, October 4, 2019 8:07 AM
  • huahi11112 さま よろしく。

    以下が参考になりませんか?。

    https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/concepts/async/#BKMK_ReturnTypesandParameters

    • Marked as answer by huahi11112 Friday, October 4, 2019 11:29 PM
    Friday, October 4, 2019 10:37 AM
  • 御回答ありがとうございます。
    書き忘れましたが、開発環境はVS2017です。
    御教授いただいた方法も、「これとて完全な対策ではない」と一般的に認識されています。
    WPFは描画制御が難しいです。
    プログラム中では他にもasync~awaitで非同期化している箇所があり、BeginInvoke~との混在はやりたくありません。

    最新のVSをお持ちであれば試して下さい。 ~Function func1() As Integerの箇所が自動的にAs Task(Of Integer) に書き変わってしまいます。
    Friday, October 4, 2019 11:08 PM
  • 御回答ありがとうございます。

    リンクの中に次の様なコードがあり、私と同じことをやっていますが、
    Async Function TaskOfTResult_MethodAsync() As Task(Of Integer)

        Dim hours As Integer
        ' . . .
        ' Return statement specifies an integer result.
        Return hours
    End Function

    これを Task returnedTask = Task_MethodAsync()と、なぜかC言語で受け取っているのが不可解ですが、returnedTaskをIntegerに変換できないでしょうか。

    非同期関数でIntegerを返すという関数を定義するということは、それほどまでにイリーガルな行為なのでしょうか。
    Friday, October 4, 2019 11:17 PM
  • 先程、自己解決です。

    (1) Private Async Function func1() As Task(Of Integer)  という定義を行う。
    (2) 呼び出す側のメソッドの定義文でasyncを記述し、 If Await func1() > 0 Then Exit Sub の様にする。

     
    Friday, October 4, 2019 11:28 PM
  • > 御教授いただいた方法も、「これとて完全な対策ではない」と一般的に認識されています。

    何をもって「一般的に認識」というのか教えてください。

    > BeginInvoke~との混在はやりたくありません。

    そういうことは私の回答には一言も書いてませんが、何か勘違いしてませんか?


    質問にアップされていたコード何をしているのか全く分かりませんでしたので、私の想像ではありますが、同期 (訂正: 非同期⇒同期) で何か実行していてその処理が終わるまで「Me.ComboBox1.Textが描き変わらない」のかなと思ってました。

    なので、質問に対する直接のではないのですが Windows Forms の DoEvent と同様な処置を入れてはどうかと提案した次第です。Await Task.Run(Sub() System.Threading.Thread.Sleep(50)) を入れるというのがその解決策になるとは思えませんでしたし。

    単なる想像なのでハズレかもしれないと言うのは最初のレスに書いた通りですが、想像が当たっていれば効果はあると思います。

    ご参考までにその具体的な例を以下に書いておきます。

    以下のコードの client.GetData(12345) と client.GetDataUsingDataContract(composite) で WCF サービスに要求を出していますが、それぞれ応答が返ってくるまで 3 秒ほどかかります。

    this.DoEvents() がないと、後者の  client.GetDataUsingDataContract(composite) の応答が返ってくるまで label に結果は反映されませんが、this.DoEvents() があれば client.GetData(12345) の応答が返ってきた時点で label に結果が反映されます。

    namespace WpfClient
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
    
            // Windows Forms アプリの Applicayion.DoEvents と同様な機能。
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            public void DoEvents()
            {
                DispatcherFrame frame = new DispatcherFrame();
                Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
                    new DispatcherOperationCallback(ExitFrame), frame);
                Dispatcher.PushFrame(frame);
            }
    
            public object ExitFrame(object f)
            {
                ((DispatcherFrame)f).Continue = false;
    
                return null;
            }
    
            // 同期呼び出し
            private void button_Click(object sender, RoutedEventArgs e)
            {
                var client = new TestService.ServiceClient();
                var composite = new TestService.CompositeType();
                label.Content = client.GetData(12345);
    
                this.DoEvents();
    
                composite.BoolValue = checkBox.IsChecked == true;
                composite.StringValue = textBox.Text;
                composite = client.GetDataUsingDataContract(composite);
                label1.Content = composite.StringValue;
            }
        }
    }


    • Edited by SurferOnWww Saturday, October 5, 2019 10:12 PM 訂正
    Saturday, October 5, 2019 1:15 AM