【问题标题】:C# LINQ ternary operator as a switchcase inside a foreachC# LINQ 三元运算符作为 foreach 中的 switchcase
【发布时间】:2013-03-05 20:55:10
【问题描述】:

我正在使用 LINQ 和 HtmlAgilitypack 从 HTML 创建数据表。 以下获取 html 表头并构造数据表列:

var nodes = htmlDoc.DocumentNode.SelectNodes("//table[@class='ps-sellers-table crts']/tr");
             nodes[0].Elements("th")
            .Skip(0)
            .Select(th => th.InnerText
            .Trim())
            .ToList()
            .ForEach(header => dt.Columns.Add(header));

到目前为止,它工作得很好,除了我需要一些定制。

  1. 选择要添加的列。
  2. 并指定列类型。

此 select 语句将完成上述两件事:

switch (header)
            {
                case ("id") : dt.Columns.Add(header,typeof(int)); break;
                case ("name") : dt.Columns.Add(header,typeof(string)); break;
                case ("price") : dt.Columns.Add(header,typeof(decimal)); break;
                case ("shipping") : dt.Columns.Add(header,typeof(decimal)); break;
                default : //skip the column and dont add it
            }

但是我对 LINQ 和 C# 真的很陌生,我想在第一个 sn-p 的 foreach 中实现上述 switch case,我知道我应该使用ternary operator,但我不确定语法。

【问题讨论】:

  • 为什么不写一个使用 switch 块的方法并调用该方法呢?
  • 我同意洪流,过度滥用三元运算符会使代码变得混乱且难以阅读。包含逻辑的方法更具可读性(如果公开,则可测试!)。我个人只使用带有布尔值的三元运算符。
  • 看起来你在列名和类型之间有一个简单的映射。为什么不直接使用Dictionary<string,Type>
  • @ThomSmith 可能是因为我还不知道那是什么,因为我还在学习!

标签: c# linq switch-statement ternary-operator


【解决方案1】:

我会将开关包装到一个方法中,然后从您的 select 语句中调用该方法。

我的版本应该是这样的:

var nodes = htmlDoc.DocumentNode.SelectNodes("//table[@class='ps-sellers-table crts']/tr");
         nodes[0].Elements("th")
        .Select(th => th.InnerText.Trim());

foreach(var node in nodes)
    AddColumnToDataTable(node, dt);

请注意,不需要Skip(0),而调用ToList() 只是为了使用List<T>.ForEach 会降低可读性并增加开销。我个人更喜欢只使用普通的foreach

话虽如此,您的方法可以重构为使用Dictionary<string, Type>。如果您将此添加到您的课程中:

Dictionary<string, Type> typeLookup;
// In your constructor:

public YourClass()
{
    typeLookup.Add("id", typeof(int));
    typeLookup.Add("name", typeof(string));
    typeLookup.Add("price", typeof(decimal));
    typeLookup.Add("shipping", typeof(decimal));
}

然后你可以把你的方法写成:

void AddColumnToDataTable(string columnName, DataTable table)
{
    table.Columns.Add(columnName, typeLookup[columnName]);
}

【讨论】:

  • 您可以直接在IEnumerable 上使用Aggregate(dt, (table, header) =&gt; dt.Columns.Add(header)) 以避免与ToList 调用混淆
  • @just.another.programmer 我还是避免了ToList 的调用。一般来说,我喜欢避免执行副作用的 LINQ 语句——在 LINQ 查询中对诸如“添加”之类的方法的任何调用都是一种不好的做法……话虽如此,如果你想的话,不需要Aggregate这样做 - 一个简单的Select 也可以...
  • 只是一个小问题,关于使用 where 子句忽略列,以下可以吗? nodes[0].Elements("th").Select(th =&gt; th.InnerText.Trim()).Where(th =&gt; th != "somecolumn");
【解决方案2】:

你可以只将开关添加到foreach,不知道为什么你必须使用三元运算符

.ToList().ForEach(header =>
{
    switch (header)
    {
       case ("id"): dt.Columns.Add(header, typeof(int)); break;
       case ("name"): dt.Columns.Add(header, typeof(string)); break;
       case ("price"): dt.Columns.Add(header, typeof(decimal)); break;
       case ("shipping"): dt.Columns.Add(header, typeof(decimal)); break;
       default: break; //skip the column and dont add it
    }
});

【讨论】:

    猜你喜欢
    • 2012-04-02
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2021-10-25
    相关资源
    最近更新 更多