提问人:Kotorfreak 提问时间:6/29/2022 最后编辑:Kotorfreak 更新时间:6/30/2022 访问量:341
DataRow.SetField() 在将数据添加到我之前删除然后重新添加的列时给出 null ref 异常
DataRow.SetField() gives a null ref exception when adding data to a column I previously deleted then added back
问:
更新
:我想我已经找到了导致这里问题的原因 https://stackoverflow.com/a/5665600/19393524
我相信我的问题在于我对 .该帖子认为,当您对它进行排序时,从技术上讲,它是对对象的写入操作,并且可能无法正确或完全传播所做的更改。这是一个有趣的读物,似乎回答了我的问题,即为什么在我对数据表进行更改后,将有效数据传递给 a 会引发此异常.DefaultView
DataTable
DataRow
更新:让我说得很清楚。我已经解决了我的问题。我只想知道为什么它会抛出错误。在我看来,代码应该可以工作,而且确实如此。第一次运行。
后我已经删除了该列,然后将其添加回来(运行此代码一次)
当我在 Visiual studio 中逐行调试代码并停在该行时:data.Rows[i].SetField(sortColumnNames[k], value);
- 该行存在
- 该色谱柱存在
value
不为 nullsortColumnNames[k]
不为 null 且包含正确的列名i
是 0
但它仍然会抛出异常。我想知道为什么。我错过了什么?
很抱歉解释太长,但不幸的是,这需要一些上下文。
所以我的问题是,我有按列对 DataTable 对象中的数据进行排序的代码。用户选择他们想要排序的列,然后我的代码对其进行排序。
我遇到了一个问题,我需要数字作为数字而不是字符串进行排序(表中的所有数据都是字符串)。例如(字符串排序将导致 1000 在 500 之前)
因此,我的解决方案是创建一个使用正确数据类型的临时列,以便正确排序数字,并且数字的原始字符串数据保持不变,但现在已正确排序。这很完美。我可以将字符串数值数据作为数值数据进行排序,而无需更改数字或数据类型的格式。
我删除了之后用于排序的列,因为我使用 defaultview 对数据进行排序并将其复制到另一个 DataTable 对象。
这部分第一次就工作正常。
问题在于用户需要对同一列执行不同的排序。我的代码将该列添加回去。(同名)然后尝试向列添加值,但随后我得到一个空引用异常“对象未设置为对象的实例”
这是我尝试过的:
- 我尝试在删除列后使用 AcceptChanges(),但这没有任何作用。
- 我尝试在 SetField() 的第一个参数中使用 DataTable.Columns.Add() 返回的列索引、名称和列对象,以防它以某种方式引用我删除的“旧”列对象(这就是我认为问题很可能出现的原因)
- 我尝试更改 .ItemArray[],但这甚至第一次都不起作用
代码如下:
以下是列名的传递方式:
private void SortByColumn()
{
if (cbAscDesc.SelectedIndex != -1)//if the user has selected ASC or DESC order
{
//clears the datatable object that stores the sorted defaultview
sortedData.Clear();
//grabs column names the user has selected to sort by and copies them to a string[]
string[] lbItems = new string[lbColumnsToSortBy.Items.Count];
lbColumnsToSortBy.Items.CopyTo(lbItems, 0);
//adds temp columns to data to sort numerical strings properly
string[] itemsToSort = AddSortColumns(lbItems);
//creates parameters for defaultview sort
string columnsToSortBy = String.Join(",", itemsToSort);
string sortDirection = cbAscDesc.SelectedItem.ToString();
data.DefaultView.Sort = columnsToSortBy + " " + sortDirection;
//copies the defaultview to the sorted table object
sortedData = data.DefaultView.ToTable();
RemoveSortColumns(itemsToSort);//removes temp sorting columns
}
}
这是添加临时列的位置:
private string[] AddSortColumns(string[] items)//adds columns to data that will be used to sort
//(ensures numbers are sorted as numbers and strings are sorted as strings)
{
string[] sortColumnNames = new string[items.Length];
for (int k = 0; k < items.Length; k++)
{
int indexOfOrginialColumn = Array.IndexOf(columns, items[k]);
Type datatype = CheckDataType(indexOfOrginialColumn);
if (datatype == typeof(double))
{
sortColumnNames[k] = items[k] + "Sort";
data.Columns.Add(sortColumnNames[k], typeof(double));
for (int i = 0; i < data.Rows.Count; i++)
{
//these three lines add the values in the original column to the column used to sort formated to the proper datatype
NumberStyles styles = NumberStyles.Any;
double value = double.Parse(data.Rows[i].Field<string>(indexOfOrginialColumn), styles);
bool test = data.Columns.Contains("QtySort");
data.Rows[i].SetField(sortColumnNames[k], value);//this is line that throws a null ref exception
}
}
else
{
sortColumnNames[k] = items[k];
}
}
return sortColumnNames;
}
这是之后删除列的代码:
private void RemoveSortColumns(string[] columnsToRemove)
{
for (int i = 0; i < columnsToRemove.Length; i++)
{
if (columnsToRemove[i].Contains("Sort"))
{
sortedData.Columns.Remove(columnsToRemove[i]);
}
}
}
注意:我已经能够通过保留列并从中删除列来解决问题,因为我在排序表上使用,这似乎可以确保不会抛出异常。data
sortedData
.Clear()
不过,我仍然想要一个答案,为什么这会引发异常。如果我在抛出异常的行之前使用,则表示该列存在并返回 true,如果有人想知道参数并且永远不会为 null。.Contains()
sortColumnNames[k]
value
答:
您的问题可能就在这里:
private void RemoveSortColumns()
{
for (int i = 0; i < data.Columns.Count; i++)
{
if (data.Columns[i].ColumnName.Contains("Sort"))
{
data.Columns.RemoveAt(i);
sortedData.Columns.RemoveAt(i);
}
}
}
如果您有 2 列,并且第一列与 匹配,则永远不会查看第二列。if
这是因为它将运行:
- 我 = 0
- 我是<列吗?计数为 2 => 是
- 是 col[0]。包含(“排序”) true => yes
- 删除 col[0]
- 我 = 1
- 我是<列吗?计数为 1 =>否
解决方案是在移除后重新调整i
private void RemoveSortColumns()
{
for (int i = 0; i < data.Columns.Count; i++)
{
if (data.Columns[i].ColumnName.Contains("Sort"))
{
data.Columns.RemoveAt(i);
sortedData.Columns.RemoveAt(i);
i--;//removed 1 element, go back 1
}
}
}
评论
i--
var columnsToRemove = (from DataColumn c in data.Columns where c.ColumnName.Contains("Sort") select c.ColumnName).ToList(); foreach (var columnName in columnsToRemove) { data.Columns.Remove(columnName); }
我通过更改方法中的几行代码来解决我的原始问题:SortByColumn()
private void SortByColumn()
{
if (cbAscDesc.SelectedIndex != -1)//if the user has selected ASC or DESC order
{
//clears the datatable object that stores the sorted defaultview
sortedData.Clear();
//grabs column names the user has selected to sort by and copies them to a string[]
string[] lbItems = new string[lbColumnsToSortBy.Items.Count];
lbColumnsToSortBy.Items.CopyTo(lbItems, 0);
//adds temp columns to data to sort numerical strings properly
string[] itemsToSort = AddSortColumns(lbItems);
//creates parameters for defaultview sort
string columnsToSortBy = String.Join(",", itemsToSort);
string sortDirection = cbAscDesc.SelectedItem.ToString();
DataView userSelectedSort = data.AsDataView();
userSelectedSort.Sort = columnsToSortBy + " " + sortDirection;
//copies the defaultview to the sorted table object
sortedData = userSelectedSort.ToTable();
RemoveSortColumns(itemsToSort);//removes temp sorting columns
}
}
我没有进行排序,而是创建一个新对象并传递它的值,然后对其进行排序。完全摆脱了我原始代码中的问题。对于任何想知道的人,我仍然认为这是 Microsoft 可能永远不会修复的 .NET 框架中的错误。我希望这将帮助将来遇到类似问题的人。
这里再次是我找到问题解决方案的链接。
https://stackoverflow.com/a/5665600data.DefaultView
DataView
data.AsDataView()
.DefaultView
评论
data.Columns
sortedData
data.Columns
RemoveSortColumns
i
for (...; i < collection.Count; ...) { /* change the number of items in `collection` in some way */ }
strings
strings