异步/等待对加载数据表的奇怪影响

Odd effect of async / await on loading a datatable

我很难理解这段代码是怎么回事。我已经 async/await 有一段时间了,但之前没有偶然发现这个问题(除非我只是没有看到我做了什么)

我正在将 CSV 文件加载到 DataTable 中,然后我想从 DataTable 中提取列名列表以便稍后操作。

在第一种方法中,我异步加载 CSV,然后分配 DataGrid 来查看数据。我无法在第一种方法中使用 _ColumnList = ...,因为无论出于何种原因,“_dtSampleCSV.Columns”都没有解析;它没有看到它是一个 DataTable。

所以我将该行移动到另一个方法,它提取列名称并将这些名称分配给另一个 DataGrid。当它遇到此方法时,_dtSampleCSV DataTable 中没有数据(没有行,没有列),但第一个 DataGrid 确实填充了数据。

我一直假设使用“await”等待线程完成后再继续。所以这不是真的,或者线程确实完成但尚未分配 DataTable。

我只能假设此时数据不存在,但 DataGrid 的源是在填充数据时设置的;表明。但是,如果 await 没有完成将数据加载到 DataTable 中,我该如何阻止执行?

private DataTable _dtSampleCSV = new DataTable();
private List<string> _ColumnList = new List<string>();

private async void btnAdd_Click(object sender, RoutedEventArgs e)
{
    spNew.Visibility = Visibility.Visible;

    OpenFileDialog openFileDialog = new OpenFileDialog();
    if (openFileDialog.ShowDialog() == true)
    {
        tbFilePath.Text = openFileDialog.FileName;
        var _dtSampleCSV = await LoadCSVAsync(openFileDialog.FileName);
            
        dgCSVExample.DataContext = _dtSampleCSV;
        dgCSVExample.Visibility = Visibility.Visible;

        SetColumnGrid();

    }
}

private void SetColumnGrid()
{
    _ColumnList = (from DataColumn dc in _dtSampleCSV.Columns.Cast<DataColumn>() select dc.ColumnName).ToList();
    dgColumnNames.DataContext = _ColumnList;  // breakpoint set here to look at _dtSampleCSV and no data exists at runtime
    dgColumnNames.Visibility = Visibility.Visible;
}

// csv method
public static async Task<DataTable> LoadCSVAsync(string filePath)
{
    using (var reader = File.OpenText(filePath))
    {
        var fileText = await reader.ReadToEndAsync();
        using (TextReader sr = new StringReader(fileText))
        {
            var adapter = new GenericParsing.GenericParserAdapter(sr);
            adapter.FirstRowHasHeader = true;
            adapter.MaxBufferSize = 4096;
            adapter.MaxRows = 3;
            DataTable dtProcess = adapter.GetDataTable();
            return dtProcess;
        }
    }
}

您的 LoadCSVAsync 方法是 static,这解释了为什么它无法访问 _dtSampleCSV 实例字段。

您的 btnAdd_Click 方法创建了一个名为 _dtSampleCSV 的局部变量,将其分配给 dgCSVExample.DataContext,然后将其丢弃。来自该局部变量的数据在 _dtSampleCSV 字段中将不可用。

更改您的方法,以便将数据分配给字段,而不是创建局部变量:

// Remove this:
// var _dtSampleCSV = await LoadCSVAsync(openFileDialog.FileName);

// Use this:
_dtSampleCSV = await LoadCSVAsync(openFileDialog.FileName);

注意: 你应该尽可能avoid async void methods