2016-04-29 16 views
2

Ich bin dabei, eine riesige if-Kette in ein Wörterbuch zu konvertieren. In einer Legacy-Lösung wird ein Excel-Export wie dies getan:Konvertieren von if-chain in regelbasiertes Wörterbuch

foreach (DataRow dr in fullData.Rows) 
{ 
    DataRow newRow = dt.NewRow(); 

    foreach (DataColumn dc in dt.Columns) 
    { 
     String s = dc.Caption; 

     if (s.Equals("ID")) 
      newRow[dc] = dr["id"]; 
     else if (s.Equals("PQ-Nr")) 
      newRow[dc] = dr["pqNummer"]; 
     else if (s.Equals("GJ")) 
      newRow[dc] = dr["geschaeftsjahr"]; 
     else if (s.Equals("Link")) 
      newRow[dc] = dr["link"]; 
     /*more complex example*/ 
     else if(s.Equals("GF")) 
     { 
      string content = ""; 
      int intVal = 0; 
      if (Int32.TryParse(dr["id"].ToString(), out intVal)) 
      { 
       List<Freigabe> liste = DBHelper.getFreigabenByPersonalTyp(intVal, Personal.GF); 
       foreach (Freigabe f in liste) 
       { 
       //build content string here 
       } 
      } 
      newRow[dc] = content.TrimEnd(); 
     } 
     /*plus around 60 more else if statements*/ 
    } 
    dt.Rows.Add(newRow); 
} 
return dt; 

Meine Idee ist es, die Regeln und die aktuelle Zeile zugewiesen off in 2 Teile geteilt. Also habe ich ein Wörterbuch erstellt:

var rules = new Dictionary<Func<string, bool>, Func<DataRow, object>>() 
{ 
    {y => y == "ID", x => x["id"] }, 
    {y => y == "PQ-Nr", x => x["pqNummer"] }, 
    //.... 
}; 

Um die aktuelle Spalte Wert zu erhalten ich folgendes:

foreach (DataRow dr in fullData.Rows) 
{ 
    DataRow newRow = dt.NewRow(); 

    foreach (DataColumn dc in dt.Columns) 
    { 
     String s = dc.Caption; 

     newRow[dc] = from r in rules 
        where r.Key(s) 
        select r.Value(dr); 
    } 
    dt.Rows.Add(newRow); 
} 
return dt; 

Der Inhalt jeder Zelle im fertigen Bericht ist jetzt: System.Linq.Enumerable+WhereSelectEnumerableIterator 2 [ System.Collections.Generic.KeyValuePair 2[System.Func 2 [System.String, System.Boolean], System.Func 2[System.Data.DataRow,System.Object]],System.Object] anstelle des Werts.

Was genau mache ich hier falsch?

+3

Ihr Linkteil 'newRow [dc] = von r in Regeln wo r.Key (s) r.Value (dr) wählen;' kann mehrere Werte zurückgeben. Begrenzen Sie die Ergebnisse einfach auf 1. –

+0

Oh Schatz. Ich bin gerade dabei, meinen Kopf gegen den Tisch zu schlagen. Möchten Sie dies als Antwort hinzufügen? – Marco

Antwort

4
rules.Where(r => r.Key(s)). 
    Select(r => r.Value(dr)). 
    FirstOrDefault(); // Should do the trick. 
5

Ich schlage vor Wechsel rules Typ:

// No lambdas, just string to string 
Dictionary<String, String> rules = new Dictionary<String, String>() { 
    {"ID", "id"}, 
    {"PQ-Nr", "pqNumme"}, 
    {"GJ", "geschaeftsjahr"}, 
    {"Link", "link"}, 
    //TODO: put other rules here 
}; 

Und so

foreach (DataRow dr in fullData.Rows) { 
    DataRow newRow = dt.NewRow(); 

    foreach (DataColumn dc in dt.Columns) 
     newRow[dc] = dr[rules[dc.Caption]]; 

    dt.Rows.Add(newRow); 
} 

bearbeiten: Bei wenigen komplexen Regeln (wie "GF" eine in der editierten Frage) Dictionary<String, String> rule kann auch helfen:

foreach (DataColumn dc in dt.Columns) { 
    String rule; 

    if (rules.TryGetValue(dc.Caption, out rule)) 
     newRow[dc] = dr[rule]; // <- all the simple rules 
    else if (dc.Caption.Equals("GF")) { // <- few specific rules 
     ... 
    } 
    } 
+0

Verdammt, ich schreibe so langsam :-) – Grundy

+0

Während dies an sich funktioniert, passt es nicht zu meinem Zweck, weil ich etwas mehr Logik in meinem Func einbeziehen muss, bevor ich die Zeichenfolge zurücksende. Ich habe es in meinem Beispiel so einfach gehalten, um einen Punkt zu machen: – Marco

+0

@Serv: Ich verstehe; Aber da die Logik hier entscheidend zu sein scheint, könnten Sie bitte einige Beispiele geben? –

Verwandte Themen