【问题标题】:Why does this LINQ throw "FormatException was unhandled"?为什么这个 LINQ 会抛出“FormatException 未处理”?
【发布时间】:2016-07-05 22:44:58
【问题描述】:

我正在尝试使用 LINQ 从通用列表中获取 val,如下所示:

private List<PriceVarianceDataAmalgamated> CombineSubsets(string unit)
{
    List<PriceVarianceDataAmalgamated> combinedSubsets = new List<PriceVarianceDataAmalgamated>();
    if (unit.Equals(CRAFTWORKS_SC))
    {
        foreach (PriceVarianceSubsetData pvsd in craftworksWeek1PVDSubsetList)
        {
            PriceVarianceDataAmalgamated pvda = new PriceVarianceDataAmalgamated
            {
                ShortName = pvsd.ShortName,
                ItemCode = pvsd.ItemCode,
                Description = pvsd.Description,
                Price1 = pvsd.Price,
                Price2 = GetPrice2(CRAFTWORKS_SC, pvsd.ShortName, pvsd.ItemCode)
            };
            pvda.Variance = "0.00";
            decimal price1 = Convert.ToDecimal(pvda.Price1);
            decimal price2 = Convert.ToDecimal(pvda.Price2);
            . . .

关键部分(没有做我想做的事)是对 GetPrice2() 的调用。该方法开始:

private string GetPrice2(string _unit, string _shortname, string _itemcode)
{
    string price2 = "0.00";
    if (_unit.Equals(CRAFTWORKS_SC))
    {
        price2 = craftworksWeek2PVDSubsetList
            .Where(x => x.ShortName.Equals(_shortname))
            .Where(x => x.ItemCode.Equals(_itemcode))
            .Select(x => x.Price).ToString();
    }
    . . .

...当我在那里分配 price2 时,分配的 val 是:

System.Linq.Enumerable+WhereSelectListIterator`2[Pivotal.PriceVarianceSubsetData,System.String]

?!?

给出的错误消息是:

System.FormatException was unhandled
  HResult=-2146233033
  Message=Input string was not in a correct format.
  Source=mscorlib
  StackTrace:
       at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
       at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt)
       at System.Convert.ToDecimal(String value)
       at Pivotal.FormMain.CombineSubsets(String unit) in c:\Projects\PriceVariance\Pivotal\Form1.cs:line 290
       at Pivotal.FormMain.GenerateAndSaveSpreadsheetFile() in c:\Projects\PriceVariance\Pivotal\Form1.cs:line 154
       at Pivotal.FormMain.buttonRun_Click(Object sender, EventArgs e) in c:\Projects\PriceVariance\Pivotal\Form1.cs:line 137
. . .

所以这条线 (290) 失败了:

List<PriceVarianceDataAmalgamated> pvdaCraftworks = CombineSubsets(CRAFTWORKS_SC);

...更具体地说是这个(第 154 行):

decimal price2 = Convert.ToDecimal(pvda.Price2);

显然错误的代码是这样的:

price2 = craftworksWeek2PVDSubsetList
    .Where(x => x.ShortName.Equals(_shortname))
    .Where(x => x.ItemCode.Equals(_itemcode))
    .Select(x => x.Price).ToString();

在它爆炸的地方单步执行时,“_shortname”和“_itemcode”都有一个有效值;完全有可能没有值可供选择,但我似乎通过为 price2 分配默认值来防御这种情况:

string price2 = "0.00";

price2 在方法结束时返回 - 也许我应该使用 catch 块并在那里分配回退值而不是从 git-go 分配?

【问题讨论】:

  • 试试.Select(x =&gt; x.Price).First().ToString();
  • 您更具体的行与之前的行相同
  • 我之前同意,但使用 FirstOrDefault 不会引发异常,而是为引用类型返回空值,为值类型返回默认值。可能会让您更容易找到问题所在。
  • @MikaelPuusaari 如果没有该项目是一个逻辑错误,那么First(抛出)可能比FirstOrDefault更好。
  • 我将其更改为 FirstOrDefault,它似乎工作得很好。 Mikael,如果你愿意,你可以回答。

标签: c# linq generics generic-list


【解决方案1】:

使用

.Select(x => x.Price).FirstOrDefault().ToString();

它不会抛出异常,而是返回引用类型的空值和值类型的默认值。可能会让您更容易找到问题所在

【讨论】:

  • “.ToString()”似乎是多余的/没有实际意义。没有它也可以正常工作,添加它会使它显示为灰色。
  • 这对我来说是新事物,但我想 LINQ 有一些新功能。我的猜测是因为你声明了变量“string price2 = “0.00”;”作为字符串而不是 var,查询已经知道将其转换为什么。感谢您的意见,我必须调查一下。
【解决方案2】:

price2 被声明为 string,但您的 LINQ 查询已写入,因此它可能会返回一个列表。

FormatException 让我觉得您可能会返回多个项目并试图将结果推送到单个变量中。将var 用于局部变量将有助于暴露此问题。

AlexD 建议.Select(x =&gt; x.Price).First().ToString()。我认为这将确保你只得到一个结果。

您可能还想考虑.Distinct() 以确保您获得单一类型的结果。如果没有首先确保没有多种类型的答案,就选择第一个项目没有多大意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 2022-01-05
    • 2010-11-09
    • 1970-01-01
    • 2019-12-03
    • 1970-01-01
    相关资源
    最近更新 更多