我有以下C#代码......
// We're essentially pivoting the data, using LINQ's GroupBy.
var pivotedOperands = Operands.GroupBy(o => new { outputid = (Guid)o[DETAILS_OUTPUTID], unitid = o[DETAILS_UNITID] })
.Select(g => new
{
PivotKey = g.Key,
c1 = g.Where(x => (int)x[DETAILS_OV_SEQUENCEID] == 1).Sum(x => double.Parse(x[DETAILS_VALUE].ToString())),
r1 = g.Where(x => (int)x[DETAILS_OV_SEQUENCEID] == 2).Sum(x => double.Parse(x[DETAILS_VALUE].ToString())),
a1 = g.Where(x => (int)x[DETAILS_OV_SEQUENCEID] == 3).Sum(x => double.Parse(x[DETAILS_VALUE].ToString()))
});
它获取操作数(它是一个List对象)中的数据,并使用GroupBy()扩展方法对数据执行数据透视。基本上c1,r1和a1都是不同DataRow对象中的值,序列ID分别为1,2和3。 (如果有必要的话,我可以进一步拘留,但我认为不会。)
因此有时c1的值可能为空。 (它不应该,但是错误在这个过程中不时发生在上游。)如果c1不是数值,double.Parse()调用将引发异常。没关系。这是我的问题。例如,如果操作数对象包含9个行,这些行将被转换为3行,而这9个值中的一个不是数字,是否可以确定哪个DataRow对象引发了异常?
例如: 如果操作数包含SequenceID和Value的以下值...
OutputID UnitID SequenceID Value
A 1 1 '0'
A 1 2 '0'
A 1 3 '0'
A 2 1 ''
A 2 2 '0'
A 2 3 '0'
B 1 1 '0'
B 1 2 '0'
B 1 3 '0'
...当我尝试通过double.Parse()方法为我的数据集的第4行处理空字符串时,我们将得到“输入字符串格式不正确”异常。我想向用户提出一个友好的例外,告诉他们哪一行是问题;不仅仅是这组数据中存在某个问题。是否有可能确切地确定导致异常的原因?
如果在Visual Studio中创建一个新的C#控制台应用程序并将以下代码转储到Main方法中,您将能够重现我的问题。
// Create a DataTable so that we can easily create new DataRows to add to our List.
DataTable dt = new DataTable();
DataColumn col = new DataColumn();
col.DataType = System.Type.GetType("System.String");
col.ColumnName = "OutputID";
dt.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Int32");
col.ColumnName = "UnitID";
dt.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Int32");
col.ColumnName = "SequenceID";
dt.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.String");
col.ColumnName = "Value";
dt.Columns.Add(col);
// Create the List and add our sample data
List<DataRow> Operands = new List<DataRow>();
DataRow dr = dt.NewRow();
dr["OutputID"] = "A";
dr["UnitID"] = "1";
dr["SequenceID"] = 1;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "A";
dr["UnitID"] = "1";
dr["SequenceID"] = 2;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "A";
dr["UnitID"] = "1";
dr["SequenceID"] = 3;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "A";
dr["UnitID"] = "2";
dr["SequenceID"] = 1;
dr["Value"] = ""; // This should cause an error.
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "A";
dr["UnitID"] = "2";
dr["SequenceID"] = 2;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "A";
dr["UnitID"] = "2";
dr["SequenceID"] = 3;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "B";
dr["UnitID"] = "1";
dr["SequenceID"] = 1;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "B";
dr["UnitID"] = "1";
dr["SequenceID"] = 2;
dr["Value"] = "0";
Operands.Add(dr);
dr = dt.NewRow();
dr["OutputID"] = "B";
dr["UnitID"] = "1";
dr["SequenceID"] = 3;
dr["Value"] = "0";
Operands.Add(dr);
// Now pivot the data
try
{
var pivotedOperands = Operands.GroupBy(o => new { outputid = o[0], unitid = o[1] })
.Select(g => new
{
PivotKey = g.Key,
c1 = g.Where(x => (int)x[2] == 1).Sum(x => double.Parse(x[3].ToString())),
r1 = g.Where(x => (int)x[2] == 2).Sum(x => double.Parse(x[3].ToString())),
a1 = g.Where(x => (int)x[2] == 3).Sum(x => double.Parse(x[3].ToString()))
});
foreach (var o in pivotedOperands)
{
Console.WriteLine(string.Format("c1 = {0}; r1 = {1}; a1 = {2}", o.c1, o.r1, o.a1));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("Done.");
Console.ReadLine();
答案 0 :(得分:2)
根据您希望信息浮出水面的方式,您可以更改结果类型以考虑失败的可能性,也可以捕获有关异常的上下文信息并在其中引发包含更多信息的新异常。 / p>
在任何一种情况下,都不要害怕使用辅助方法。例如,假设您通过创建如下方法来摆脱选择器中的重复代码:
string GetSumOrErrorMessage(int idToMatch, IEnumerable<DataRow> dataRow)
{
try
{
var sum = dataRow.Where(x => (int)x[2] == idToMatch).Sum(x => double.Parse(x[3].ToString()));
return sum.ToString();
}
catch (Exception)
{
return "Error happened here"; // or something more specific
}
}
现在您可以像这样更改查询:
var pivotedOperands = Operands.GroupBy(o => new { outputid = o[0], unitid = o[1] })
.Select(g => new
{
PivotKey = g.Key,
c1 = GetSumOrErrorMessage(1, g),
r1 = GetSumOrErrorMessage(2, g),
a1 = GetSumOrErrorMessage(3, g)
});
你的输出变成了:
c1 = 0; r1 = 0; a1 = 0 c1 = Error happened here; r1 = 0; a1 = 0 c1 = 0; r1 = 0; a1 = 0
如果您喜欢这种模式,而不是只返回string
,您可能需要查看可以帮助解决此问题的专用Monadic类型。例如,您可以创建一个在操作成功时具有通用值的类,或者在没有操作时创建错误消息的类。您可以创建各种扩展方法和帮助程序,以便更容易处理,类似于my CallMeMaybe library允许您尝试解析值的方式,但如果解析失败则返回空Maybe<>
。 (例如Maybe.From(x[3].ToString()).ParseInt64().Select(i => i.ToString()).Else("Error happened here")
)。
或者,如果您实际上想要在输入错误时暂停,但仍想知道错误输入的位置,则可以捕获并抛出:
double GetSum(int idToMatch, IGrouping<object, DataRow> dataRows)
{
try
{
return dataRows.Where(x => (int)x[2] == idToMatch).Sum(x => double.Parse(x[3].ToString()));
}
catch (Exception e)
{
throw new Exception($"Failure when matching {idToMatch} with group {dataRows.Key}", e);
}
}
...
var pivotedOperands = Operands.GroupBy(o => new { outputid = o[0], unitid = o[1] })
.Select(g => new
{
PivotKey = g.Key,
c1 = GetSum(1, g),
r1 = GetSum(2, g),
a1 = GetSum(3, g)
});
输出:
c1 = 0; r1 = 0; a1 = 0 Failure when matching 1 with group { outputid = A, unitid = 2 }
答案 1 :(得分:1)
您尝试使用TryParse
来解决异常问题。如果TryParse为false,则默认为零(0
)
.Sum(x => {
double value = 0;
return double.TryParse(x[DETAILS_VALUE].ToString(), out value) ? value : 0;
})