在LINQ中将字符串转换为整数

6

我有一个查询DataTable的LINQ查询。在DataTable中,字段是字符串,我需要与整数进行比较,基本上是这样的:

if ((electrical >= 100 && electrical <= 135) || electrical == 19)
{
    // The device passes
}

问题在于,我尝试在LINQ中这样做:
        var eGoodCountQuery = 
            from row in singulationOne.Table.AsEnumerable()
            where (Int32.Parse(row.Field<String>("electrical")) >= 100 &&
                   Int32.Parse(row.Field<String>("electrical")) <= 135) &&
                   Int32.Parse(row.Field<String>("electrical")) != 19 &&
                   row.Field<String>("print") == printName
            select row;

我不断收到异常:

输入字符串格式不正确

主要问题出现在 electrical == "" 时。


5
如果您将 electrical 字段改为 row.Field<int> 而不是 row.Field<String>,这个方法就无法正常工作吗? - Mike Perrenoud
@MichaelPerrenoud,那样行不通。 - Anthony Pegram
3
该字段实际值为多少?如果它确实是数字字符串,那么你的代码应该能够工作。但只要有一个行包含非数字值,它就会失败。是否存在包含非数字值的行? - Kenneth
3
“电气”领域实际上包含什么?这个对象的实际类型和内容是什么?也许它无法被解析为整数,或者可能根本不是字符串?使用调试器查看它失败时的情况。 - Servy
3
错误表明这些假设中至少一个是错误的:“输入字符串不是正确的格式。” 这可能是因为空字符串或者字符串包含了非整数值。没有其他解释。在调试器中视觉检查您的数据表格。里面有什么?(还要注意,“105.0”和“apple”同样无效。) - Anthony Pegram
显示剩余7条评论
4个回答

6
很不幸,这个框架没有提供一个很好的方式来处理解析失败的情况。所提供的只有抛出异常或使用out参数,这两种方式都不能很好地与linq查询配合使用。如果你正在解析的任何一个值失败了,整个查询就会失败,而你真的无法使用out参数。你需要提供一种不会抛出异常,也不需要使用out参数来处理解析的方法。
你可以用许多方法来处理这个问题。实现一种机制,在解析失败时返回一些默认的标记值。
public static int ParseInt32(string str, int defaultValue = 0)
{
    int result;
    return Int32.TryParse(str, out result) ? result : defaultValue;
}

或者我建议返回一个可空值(null表示失败)。
public static int? ParseInt32(string str)
{
    int result;
    return Int32.TryParse(str, out result) ? result : null;
}

这将极大地简化您的查询,同时仍保持可读性。
public bool GetElectricalStatus(string printName)
{
    var query =
        from row in singulationOne.Table.AsEnumerable()
        where row.Field<string>("print") == printName
        // using the nullable implementation
        let electrical = ParseInt32(row.Field<string>("electrical"))
        where electrical != null
        where electrical == 19 || electrical >= 100 && electrical <= 135
        select row;
    return !query.Any();
}

顺带一提,你使用 Convert.ToInt32() 方法是错误的。它与调用 Int32.Parse() 相同,并且不会返回可空值,在失败时将引发异常。


4
我会检查列中的数据是否包含前导/尾随空格,即"15 "而不是"15",如果是的话(或可能是),请在尝试转换之前对其进行修剪:

Int32.Parse(row.Field<String>("electrical").Trim())

顺便说一句:与错误无关,但我建议使用let语句引入一个局部变量,并进行一次转换:

let x = Int32.Parse(row.Field<String>("electrical").Trim()) 
where x >= 100...

这并不能解决问题。 - kformeck
这个不起作用,会抛出异常:未实现。内部异常信息:LINQ to Entities 不识别 'Int32 Parse(System.String)' 方法,该方法无法转换为存储表达式。 - spikey
如果在执行操作之前完成数据集,则可以使其切换到对象的 Linq,从而使其正常工作。 - John Lord

0

我什么都做不了,所以我重新做了整个方法:

    public bool GetElectricalStatus(string printName)
    {
        List<object> eGoodList = new List<object>();
        var eGoodCountQuery =
            from row in singulationOne.Table.AsEnumerable()
            where row.Field<String>("print") == printName
            select row.Field<String>("electrical");

        foreach (var eCode in eGoodCountQuery)
        {
            if (!string.IsNullOrEmpty(eCode.ToString()))
            {
                int? eCodeInt = Convert.ToInt32(eCode);
                if (eCodeInt != null &&
                    (eCodeInt >= 100 && eCodeInt <= 135) || eCodeInt == 19)
                {
                    eGoodList.Add(eCode);
                }
            }
        }
        if (eGoodList.Count() > 0)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

主要问题出现在 electrical == "" 的情况下。

请注意,如果您在更新问题时提供了关于空字符串的有用信息,人们可以使您的原始查询起作用。 - Anthony Pegram

0
为什么不编写一个函数来进行评估,并在Linq查询中调用它。在函数中加入逻辑来检查所包含数据的有效性(如果无法解析数据,应返回 "false")。
bool IsInRange(string text, int lower, int upper, params int[] diqualifiers)
{
  int value = int.MinValue;
  if (!int.TryParse(text, out value)) {
    return false;
  }
  if (!(value >= lower && value <= upper)) {
    return false;
  }
  if (disqualifiers != null && disqualifiers.Any(d => d == value)) {
    return false;
  }
  return true;
}

Linq 查询...

var eGoodCountQuery = 
            from row in singulationOne.Table.AsEnumerable()
            where 
              IsInRange(row.Field<String>("electrical"), 100, 135, 19) 
              && row.Field<String>("print") == printName
            select row;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接