4

我的 DB2/400 有一个简单的心跳方法:

public bool CheckConnection()
        {
            try
            {
                using (OleDbConnection db = new OleDbConnection( this.conString ))
                {
                    OleDbCommand cmd = new OleDbCommand();
                    cmd.CommandText = "select 1 from sysibm.sysdummy1";
                    cmd.Connection = db;
                    db.Open();
                    cmd.ExecuteReader();
                    db.Close();
                    return true;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

我想在我的应用程序运行时使用它,当然我不想保留表单其余部分的执行。

我的主要方法是:

public FrmMain()
    {
        InitializeComponent();
        PrepareFormTexts();
        PrepareFormData();
        PrepareStateClass();
        CheckDbConnection();
        //Initialize Data Access for AS400
        Dal = JDE8Dal.Instance;
        Dal.conString = Properties.Settings.Default.conAS400;
        //Initialize Icons
        picCon.Image = Properties.Resources.ledGreen;
        picStatus.Image = Properties.Resources.ledGreen;
        // Load recording from file if they exist
        PrepareRecordings(AppState.DataFileName,'|');
    }

CheckDbConnection 方法:

    private async Task<bool> CheckDbConnection()
    {
        return await Task.Factory .StartNew(() => Dal.CheckConnection());
    }

我认为它运行良好,但我收到警告

警告 1 由于不等待此调用,因此在调用完成之前继续执行当前方法。考虑将“等待”运算符应用于调用结果。

我应该忽略它吗?我应该将异步放在主要方法中吗?

更新:在下面讨论之后,我发现由于我使用 .NET 4.0 的异步包,我不能真正使我的 dal 方法成为非阻塞的。我唯一能做的就是使用 async/await + task.factory.startnew 以使我的应用程序在 dal 在后台工作时保持工作。

下面的代码:

public FrmMain()
    {
        InitializeComponent();
        Load += FormLoadInit;
    }

    private async void FormLoadInit(object sender, EventArgs e)
    {
        PrepareFormTexts();
        PrepareFormData();
        PrepareStateClass();
        txtLot.Select();
        //Initialize Data Access for AS400
        Dal = JDE8Dal.Instance;
        Dal.conString = Properties.Settings.Default.conAS400;
        // Load recording from file if they exist
        PrepareRecordings(AppState.DataFileName, '|');
        bool cn = await Task.Factory.StartNew(() => Dal.CheckConnection());
        //Initialize Icons
        picCon.Image = cn ? Resources.ledGreen : Resources.ledRed;
        picStatus.Image = Properties.Resources.ledGreen;

    }
4

4 回答 4

3

警告告诉您的是,您正在有效地触发然后忘记此异步任务。你从来没有真正使用过操作的结果,你甚至不会存储它Task本身以允许任何未来的代码依赖它的结果(甚至知道它何时完成)。

这不会破坏任何东西,但也不是很有帮助。您也可以不调用该方法。现在,在您的情况下,这只是一个虚拟列表,因此您需要问自己要测试什么。您想在表单上显示一些虚拟值作为概念证明吗?如果是这样,您的代码将需要进行一些更改才能到达那里。

要实际使用查询的结果,您将需要await它,并且您不能在构造函数中执行此操作。您需要将代码移动到Form Load事件处理程序并将处理程序标记为async以便您可以await在其中使用。

您遇到的另一个问题是,要创建异步方法,您将启动一个将在线程池中运行的新任务,然后让它执行阻塞方法。使用 async/await 模型的主要优点是您不需要这样做。您应该使用直接为您提供 aTask<T>作为其返回值且不会阻塞的数据库查询方法。然后,您可以await处理这些任务(或仅返回它们),以便您的应用程序在等待时没有线程被阻塞。

您的CheckConnection方法应如下所示:

public async Task<bool> CheckConnection()
{
    try
    {
        using (OleDbConnection db = new OleDbConnection(this.conString))
        {
            OleDbCommand cmd = new OleDbCommand();
            cmd.CommandText = "select 1 from sysibm.sysdummy1";
            cmd.Connection = db;
            db.Open();
            await cmd.ExecuteReaderAsync();
            return true;
        }
    }
    catch (Exception)
    {
        return false;
    }
}

CheckDbConnection那么就不需要存在了。不需要包装CheckConnectionaTask因为它已经返回了一个任务。

于 2012-12-04T19:49:32.883 回答
0

构造函数不能是异步的(至少我每次尝试时总是会遇到编译器错误。但是事件处理程序可以是。我认为大多数初始化代码无论如何都属于 Form.Load 处理程序。

public FrmMain()
{
    InitializeComponent();
    Load+=OnLoaded;
}

private async void Onloaded(object sender, EventArgs args)
{
    PrepareFormTexts();
    PrepareFormData();
    PrepareStateClass();
    await CheckDbConnection();
    //Initialize Data Access for AS400
    Dal = JDE8Dal.Instance;
    Dal.conString = Properties.Settings.Default.conAS400;
    //Initialize Icons
    picCon.Image = Properties.Resources.ledGreen;
    picStatus.Image = Properties.Resources.ledGreen;
    // Load recording from file if they exist
    PrepareRecordings(AppState.DataFileName,'|');
}
于 2012-12-04T19:50:21.073 回答
0
public FrmMain()
{
    InitializeComponent();
    PrepareFormTexts();
    PrepareFormData();
    PrepareStateClass();
    Task delayTask = CheckDbConnection();
    //Initialize Data Access for AS400
    Dal = JDE8Dal.Instance;
    Dal.conString = Properties.Settings.Default.conAS400;
    //Initialize Icons
    picCon.Image = Properties.Resources.ledGreen;
    picStatus.Image = Properties.Resources.ledGreen;
    // Load recording from file if they exist
    PrepareRecordings(AppState.DataFileName,'|');
}
于 2012-12-04T19:56:22.173 回答
0

为了完成您的范围,也许您应该考虑Reactive Extensions Framework。以下是基于您的问题示例的示例实现。您需要将标签添加到表单(label1label2)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

//get Reactive Extensions and reference them in your project.
//Reactive Extensions for .NET (Rx .NET) http://msdn.microsoft.com/en-us/data/gg577610
using System.Reactive.Linq;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Load += Form1_Load;
        }

        async void Form1_Load(object sender, EventArgs e)
        {
            //do independent stuff
            PrepareSomeStuff();

            //notify the DB checking
            label1.Text = "Checking DB";

            //declare an IObservable
            IObservable<bool> startAsync = Observable.Start<bool>(() => CheckConnection()).FirstAsync<bool>();

            //do some other independent stuff
            PrepareSomeOtherStuff();

            //wait for the IObservable to return data
            bool isDbReady = await startAsync;
            label1.Text = "Ready";
        }

        private void PrepareSomeOtherStuff()
        {
            //do some other stuff
            label2.Text += "\r\nDo some other stuff";
        }

        private void PrepareSomeStuff()
        {
            //do stuff
            label2.Text = "Do stuff";
        }

        private bool CheckConnection()
        {
            //do stufff
            System.Threading.Thread.Sleep(5000);
            return true;
        }
    }
}
于 2012-12-04T21:52:46.043 回答