gpt4 book ai didi

c# - Linq 扩展方法和错误处理

转载 作者:太空宇宙 更新时间:2023-11-03 22:51:20 25 4
gpt4 key购买 nike

我有以下 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()))
});

它获取 Operands(这是一个 List 对象)中的数据,并使用 GroupBy() 扩展方法对数据执行透视。本质上,c1、r1 和 a1 都是序列 ID 分别为 1、2 和 3 的不同 DataRow 对象中的值。 (如果有必要,我可以对此进行更多的讨论,但我认为不会。)

所以有时 c1 的值可能为空。 (这不应该,但错误不时会在流程的更上游发生。)如果 c1 不是数值,则 double.Parse() 调用将引发异常。没关系。这是我的问题。例如,如果 Operands 对象包含 9 行,这些行将被转换为 3 行,并且这九个值中的一个不是数字,是否可以确定哪个 DataRow 对象引发了异常?

例子:如果 Operands 包含以下 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 行处理空字符串时,我们将得到一个“输入字符串格式不正确”的异常。我想向用户提出一个友好的异常(exception),告诉他们哪一行是问题所在;不仅仅是这组数据的某处存在问题。是否可以准确识别导致异常的原因?

如果您在 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();

最佳答案

根据您希望信息显示的方式,您可以更改结果类型以说明失败的可能性,或者您可以捕获有关异常的上下文信息并抛出包含更多信息的新异常。

无论哪种情况,都不要害怕使用辅助方法。例如,假设您通过创建如下方法摆脱了选择器中的重复代码:

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 }

关于c# - Linq 扩展方法和错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47208491/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com