2017-11-09 9 views
1

I가 다음과 C# 코드 ...Linq를 확장하는 방법 및 오류 처리

그것은 (a List 객체이다) 피연산자의 데이터를 받아 피봇을 수행 GROUPBY() 확장 방법을 사용
// 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())) 
     }); 

데이터에. 본질적으로 c1, r1 및 a1은 각각 시퀀스 ID가 1, 2 및 3 인 다른 DataRow 개체의 모든 값입니다. (필요한 경우 더 많이 감금 할 수 있지만 그렇지 않을 것이라고 생각합니다.)

때로는 c1의 값이 비어있을 수 있습니다. (그럴 필요는 없지만 수시로 프로세스의 상위 단계에서 버그가 발생했습니다.) c1이 숫자 값이 아니면 double.Parse()를 호출하면 예외가 발생합니다. 괜찮아. 여기 내 문제가있다. Operands 개체에 예를 들어 3 행으로 피벗되고 9 개의 값 중 하나가 숫자가 아닌 9 개의 행이 포함되어 있으면 예외를 발생시킨 DataRow 개체를 결정할 수 있습니까?

예 : 피연산자가 SequenceID과 가치에 대해 다음 값을 포함 할 경우 ...

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() 메서드를 통해 빈 문자열을 처리하십시오. 사용자에게 어떤 행이 문제인지 친숙한 예외를 제기하고 싶습니다. 이 데이터 세트의 어딘가에 문제가 있다는 것만이 아닙니다. 예외의 원인을 정확히 식별 할 수 있습니까?

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(); 
+1

기본값. tryparse가 false 인 경우 인덱스를 기록합니다. 또는 tryparse false로 기본값 0 ( – Nkosi

답변

2

그 안에.

두 경우 모두 도우미 메서드를 사용하는 것을 두려워하지 마십시오.

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 

당신이 만약이 같은 패턴이 아니라 단지 012,392을 돌아보다이 작업에 도움이되는 특수화 된 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 } 
+2

)이 아름답습니다. 이 일은 결코 내게 일어나지 않았다. 도우미 메서드를 사용하면 예외적 인 경우를 처리하기 위해 실행을 제어 할 수 있습니다. 고맙습니다. – DeadZone

1

예외를 피하기 위해 TryParse을 사용해보십시오. TryParse이 거짓 인 경우를 제외하고 해결하기 위해 TryParse를 사용하여 내 머리 위로는 또한 인덱스를 선택 사용하여 방금 제로 (0)

.Sum(x => { 
    double value = 0; 
    return double.TryParse(x[DETAILS_VALUE].ToString(), out value) ? value : 0; 
}) 
+0

도움 주셔서 감사합니다. StriplingWarrior의 대답은 파싱에 실패 할 경우 기본값을 사용하거나 예외를 발생시키고 실행을 중단 할 수있는 유연성을 제공했기 때문에 나왔습니다. (정확히 내가 원하는 것입니다.) – DeadZone

+0

@DeadZone 괜찮습니다. 실제로 예외를 잡으려는 경우 더 나은 선택이었습니다. 도와 드리겠습니다. – Nkosi