异步/等待对加载数据表的奇怪影响
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。
我很难理解这段代码是怎么回事。我已经 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。