【问题标题】:Converting if-chain into rule-based dictionary将 if-chain 转换为基于规则的字典
【发布时间】:2016-04-29 07:34:22
【问题描述】:

我坚持将一个巨大的 if 链转换为字典。在旧版解决方案中,Excel 导出是这样完成的:

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;

我的想法是将规则和实际分配的行分成两部分。所以我创建了一个字典:

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

为了获取当前列值,我执行以下操作:

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;

完成报告中每个单元格的内容现在是:System.Linq.Enumerable+WhereSelectEnumerableIterator2[System.Collections.Generic.KeyValuePair2[System.Func2[System.String,System.Boolean],System.Func2[System.Data.DataRow,System.Object]],System.Object],而不是它的价值。

我到底做错了什么?

【问题讨论】:

  • 您的 linq 部分 newRow[dc] = from r in rules where r.Key(s) select r.Value(dr); 可以返回多个值。只需将结果限制为 1。
  • 天哪。我现在还没有把头撞在桌子上。想要将此添加为答案?

标签: c# linq dictionary datatable


【解决方案1】:

我建议更改rules类型:

// 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
};

所以

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);
}

编辑:如果有复杂的规则(如编辑问题中的"GF" 之一)Dictionary&lt;String, String&gt; rule 也可以提供帮助:

   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
       ...
     }
   }

【讨论】:

  • 该死,我写得太慢了:-)
  • 虽然这本身可以工作,但它不符合我的目的,因为在返回字符串之前我需要在我的 Func 中包含更多逻辑。我只是在我的示例中保持简单以说明观点
  • @Serv:我明白了;但是由于这里的逻辑似乎很重要,请您提供一些示例吗?
  • @Serv,所以你可以改为将字符串保存为值,然后像newRow[dc] = dr[rules[dc.Caption](dr)];一样调用
  • @DmitryBychenko 我在问题中添加了一个更复杂的示例来说明我的观点。我正在模块化整个整体结构,所以这也是一个需要更改的主题,很可能会被导出到自己的规则集中(加上尽可能多地更改为英语......)。
【解决方案2】:
rules.Where(r => r.Key(s)).
    Select(r => r.Value(dr)).
    FirstOrDefault(); // Should do the trick.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-22
    • 2021-08-27
    • 1970-01-01
    • 2019-02-16
    相关资源
    最近更新 更多