关于'system.invalidoperationexception
'的问题很多,但是没有一个问题能帮助我解决这个问题。
我有一个datatable
(tab2tableExtra
),它从另一个datatable
(tab2table
)获取其值,而另一个tab2tableExtra
(tab2table
)从数据库获取值。 tab2table
仅包含4行8列,并且其所有值(禁止列[0])均根据MLevel
计算得出。具体来说,RLevel
中的两列用于驱动for循环,而这似乎是问题的症结所在。它们是MLevel
和RLevel
,在下面的代码中显示。
当DBNull.Value
列和tab2tableExtra
列都具有一些非null值时,一切都将正常工作。但是,如果这些列之一全为空(MLevel
-有时可能会发生),那么似乎出了问题。有趣的是,它实际上并没有导致代码中断,但是似乎与RLevel
中的计算值混淆了,因为整个表为空(列[0]除外,该列仅是1,2, 3,4)。
在调试时,当from
或// Add values to tab2tableExtra
// Add Levels columns
DataRow row = tab2tableExtra.NewRow();
for (int i = 1; i < 5; i++)
{
row = tab2tableExtra.NewRow();
row["Level"] = i;
tab2tableExtra.Rows.Add(row);
}
// Add participation rate column values
DataRow dr = tab2tableExtra.Rows[0];
int rowCount = tab2table.Rows.Count;
/*int countnumM = tab2table.AsEnumerable().Where(x => int.Parse(x["MLevel"].ToString()) == 1 ||
int.Parse(x["MLevel"].ToString()) == 2 || int.Parse(x["MLevel"].ToString()) == 3 ||
int.Parse(x["MLevel"].ToString()) == 4).ToList().Count;*/
int countnumM = tab2table.AsEnumerable().Select(x => int.TryParse(x["MLevel"].ToString(), out var d) ? d : (int?)null).Where(x => x >= 1 && x <= 4).Count();
int countnumRW = tab2table.AsEnumerable().Select(x => int.TryParse(x["RLevel"].ToString(), out var d) ? d : (int?)null).Where(x => x >= 1 && x <= 4).Count();
/*int countnumRW = tab2table.AsEnumerable().Where(x => int.Parse(x["RLevel"].ToString()) == 1 || int.Parse(x["RLevel"].ToString()) == 2 ||
int.Parse(x["RLevel"].ToString()) == 3 || int.Parse(x["RLevel"].ToString()) == 4).ToList().Count;*/
for (int i = 1; i < 5; i++)
{
if (countnumM > 0)
{
float levelPercM = Convert.ToInt32(tab2table.Compute("COUNT(MLevel)", "MLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][1] = Math.Round(100 * levelPercM / countnumM, 2);
}
else
tab2tableExtra.Rows[i - 1][1] = null;
if (countnumRW > 0)
{
decimal levelPercRW = Convert.ToDecimal(tab2table.Compute("COUNT([RLevel])", "RLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][2] = Math.Round(100 * levelPercRW / countnumRW, 2);
}
else
tab2tableExtra.Rows[i - 1][2] = null;
}
// Add the rest of the column values that only require a single number
tab2tableExtra.Rows[0][3] = rowCount;
if (countnumM > 0)
tab2tableExtra.Rows[0][4] = 100*countnumM/rowCount;
else
tab2tableExtra.Rows[0][4] = null;
if (countnumRW > 0)
tab2tableExtra.Rows[0][5] = 100*countnumRW/rowCount;
else
tab2tableExtra.Rows[0][5] = null;
decimal RWavg = Convert.ToDecimal(tab2table.Compute("AVG([ROverall])", ""));
decimal Mavg = Convert.ToDecimal(tab2table.Compute("AVG([MOverall])", ""));
tab2tableExtra.Rows[0][6] = RWavg;
tab2tableExtra.Rows[0][7] = Mavg;
(但不是全部)都包含所有null时,我看到一个'system.invalidoperationexception tab2table
this`,如下图所示。导致代码执行此操作的原因是,在一次迭代后退出for循环,然后不执行任何其他计算。
此消息来自以下代码:
MLevel
作为参考,当我使用RLevel
和{{1}}都具有至少一个非空值的{{1}}进行调试时,我看到以下内容:
如果有人知道如何解决这个问题,甚至只是知道为什么会发生,那将非常有用。
答案 0 :(得分:1)
在这些代码行中:
int countnumM = tab2table.AsEnumerable()
.Select(x => int.TryParse(x["MLevel"].ToString(), out var d) ? d : (int?)null)
.Where(x => x >= 1 && x <= 4).Count();
int countnumRW = tab2table.AsEnumerable()
.Select(x => int.TryParse(x["RLevel"].ToString(), out var d) ? d : (int?)null)
.Where(x => x >= 1 && x <= 4).Count();
您正在使用int.TryParse
来读取x["MLevel"]
的值。
如果x["MLevel"].ToString()
未返回可解析为string
的{{1}},则int
将返回false。其中包括int.TryParse
是否为x
。那不会被解析为DBNull.Value
。
然后,在int
之后,您将拥有:TryParse
换句话说,如果? d : (int?)null)
返回true-能够解析,则您选择的是TryParse
-解析后的值。
但是,如果无法解析该值-d
返回false-那么您将返回TryParse
-实际上为空。
最后,您要过滤1到4之间的值的结果,然后计算这些结果的数量:
(int?)null
正如您所描述的,如果存在一些非空值,那么.Where(x => x >= 1 && x <= 4).Count();
可能会返回一个或多个。但是,如果存在所有个空值,则Count
将等于0,因为没有值在1到4之间。
在这种情况下,.Count
和/或countnumM
等于0。
进一步,您正在设置一些其他值countnumRW
和if countnumM > 0
。但是它们不大于0。它们是0。如果它们是0,则您的代码将执行您期望的操作:
if countnumRW > 0
要澄清其他部分- for (int i = 1; i < 5; i++)
{
if (countnumM > 0) // this is == 0
{
float levelPercM = Convert.ToInt32(tab2table.Compute("COUNT(MLevel)", "MLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][1] = Math.Round(100 * levelPercM / countnumM, 2);
}
else // This is what's happening
tab2tableExtra.Rows[i - 1][1] = null;
if (countnumRW > 0) // this is == 0
{
decimal levelPercRW = Convert.ToDecimal(tab2table.Compute("COUNT([RLevel])", "RLevel =" + i.ToString()));
tab2tableExtra.Rows[i - 1][2] = Math.Round(100 * levelPercRW / countnumRW, 2);
}
else // This is what's happening
tab2tableExtra.Rows[i - 1][2] = null;
}
:
当您进入调试器并检查变量的属性时,它将尝试显示每个属性的值。这就是图像中的属性列表-它是InvalidOperationException
的所有属性。
其中一些可能是您不使用或不在意的属性,但是当它尝试读取这些属性以便向您显示它们时,该属性将引发异常。因此,现在,它代替了一个属性值,它向您显示了尝试读取该属性时遇到的异常。
这是可以理解的,因为您正在调试试图弄清楚代码中正在发生什么,然后看到异常。您想知道它们是否与问题有关。
通常不是,因为如果您的代码引发异常,则它将停止执行您的代码。这是一个例外,您需要弄清楚。但是,如果它没有阻止代码运行,并且是甚至没有使用的某个框架类(例如this
)上的一个属性,那么通常可以忽略它。
答案 1 :(得分:0)
正如Scott Hannen所说,这里的问题与'system.invalidoperationexception'
异常无关。对于遇到类似问题的人,实际的问题是null
。
事实证明,在C#数据表中无法处理null
值。它并没有给出错误,而只是遇到数据表时就停止填充数据表。为了解决此问题,必须确保使用DBNull.Value
。因此,例如,在相关代码中,将所有null
更改为DBNull.Value
将解决此问题。