Как я могу определить, какой элемент вызывает переполнение?

У меня есть этот код:

String testData = File.ReadAllText("siteQueryTest.txt");
XDocument xmlDoc = XDocument.Parse(testData);
List<SiteQuery> sitequeries =
 (from sitequery in xmlDoc.Descendants("SiteQuery")
  select new SiteQuery
  {
      Id = Convert.ToInt32(sitequery.Element("Id").Value),
      UPCPackSize = Convert.ToInt32(sitequery.Element("UPCPackSize").Value),
      UPC_Code = sitequery.Element("UPC_Code").Value,
      crvId = sitequery.Element("crvId").Value,
      dept = Convert.ToInt32(sitequery.Element("dept").Value),
      description = sitequery.Element("description").Value,
      openQty = Convert.ToDouble(sitequery.Element("openQty").Value),
      packSize = Convert.ToInt32(sitequery.Element("packSize").Value),
      subDept = Convert.ToInt32(sitequery.Element("subDept").Value),
      unitCost = Convert.ToDecimal(sitequery.Element("unitCost").Value),
      unitList = Convert.ToDecimal(sitequery.Element("unitList").Value),
      vendorId = sitequery.Element("vendorId").Value,
      vendorItem = sitequery.Element("vendorItem").Value,
  }).ToList<SiteQuery>();

тестовые данные:

<SiteQueries><SiteQuery><Id>00006000002</Id><UPCPackSize>1</UPCPackSize><UPC_Code>00006000002</UPC_Code><crvId></crvId><dept>8</dept><description>ZZ</description><openQty>0.0</openQty><packSize>1</packSize><subDept>80</subDept><unitCost>1.25</unitCost><unitList>5.0</unitList><vendorId>CONFLICT</vendorId><vendorItem>123456</vendorItem></SiteQuery>
. . . // gazillions of other SiteQuery "records"
<SiteQuery><Id>5705654</Id><UPCPackSize>1</UPCPackSize><UPC_Code>5705654</UPC_Code><crvId></crvId><dept>2</dept><description>what do you want</description><openQty>0.0</openQty><packSize>1</packSize><subDept>0</subDept><unitCost>0.55</unitCost><unitList>1.62</unitList><vendorId></vendorId><vendorItem></vendorItem></SiteQuery></SiteQueries>

Но я получаю следующее исключение времени выполнения с этим кодом и данными:

System.OverflowException was unhandled
  _HResult=-2146233066
  _message=Value was either too large or too small for an Int32.
  HResult=-2146233066
  IsTransient=false
  Message=Value was either too large or too small for an Int32.
  Source=mscorlib
  StackTrace:
       at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
       at System.Convert.ToInt32(String value)
       at Sandbox.Form1.<button56_Click>b__e(XElement sitequery) in c:\HoldingTank\Sandbox\Form1.cs:line 2041
       at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
    . . .
  InnerException: 

В каждой "записи" xml есть несколько значений int (4); есть тысячи записей. Как я могу, не пытаясь надеть шляпу Человека дождя (которая мне не очень подходит), определить, какое именно значение является проблематичным, вызывающим переполнение или недополнение?

Если это потеря значимости (в сообщении об исключении говорится как «OverflowException», так и «Значение было либо слишком большим, либо слишком маленьким для Int32», может ли это быть вызвано пустым значением для одного из этих четырех членов int? Если да, то как я могу сказать ему рассматривать пустое значение как 0?


person B. Clay Shannon    schedule 07.01.2015    source источник
comment
Поймать исключение, сломать обработчик, проверить переменные и прогресс?   -  person Martin James    schedule 07.01.2015
comment
Почему бы не использовать decimal вместо int?   -  person DrKoch    schedule 07.01.2015
comment
It says: c:\HoldingTank\Sandbox\Form1.cs:line 2041`, что это за строка?   -  person jessehouwing    schedule 07.01.2015
comment
Convert.ToInt32(sitequery.Element("foo").Value) требует специального метода, который принимает sitequery и Foo в качестве аргументов. Вы бы поймали преступника в мгновение ока.   -  person Wiktor Zychla    schedule 07.01.2015
comment
@DrKoch: Почему это поможет?   -  person B. Clay Shannon    schedule 07.01.2015
comment
@jessehouwing: это выбор нового SiteQuery   -  person B. Clay Shannon    schedule 07.01.2015
comment
Что ж, этот код UPC определенно может быть слишком большим для int32 только из-за количества цифр. Если начальное число равно 1, оно переполнится.   -  person Mike Zboray    schedule 07.01.2015
comment
@MartinJames: нет пользовательского кода, который можно взломать.   -  person Ben Voigt    schedule 07.01.2015
comment
@mikez: Похоже, код UPC — одно из немногих полей, которые не преобразуются. Возможно оставили в виде строки.   -  person Ben Voigt    schedule 07.01.2015
comment
Я бы добавил, что вы можете изменить конструкторы siteQuery для обработки и проверки аргументов, а не внутри выражения LINQ, что упростит отлов исключения.   -  person Bill Dinger    schedule 07.01.2015
comment
Поскольку у вашего Id есть первые цифры, я бы все равно использовал для него string, иначе вы потеряете эти цифры.   -  person Matt Burland    schedule 07.01.2015
comment
@mikez: Да, как говорит Бен Фойгт, код UPC — это строка.   -  person B. Clay Shannon    schedule 07.01.2015
comment
@BenVoigt да, я имел в виду идентификатор.   -  person Mike Zboray    schedule 07.01.2015
comment
@B.ClayShannon да, я имел в виду идентификатор, это то же значение, но оно преобразуется в целое число. Очевидное решение состоит в том, чтобы переместить это в метод и внести некоторые записи в журнал, чтобы вы могли найти оскорбительную запись.   -  person Mike Zboray    schedule 07.01.2015
comment
Закомментируйте все Convert.Int32 строки. Раскомментируйте их один за другим, пока он снова не сломается. Определите, какое поле вызывает проблему с uint (если оно все равно не может быть отрицательным) или Int64. Если у вас нет причин полагать, что один из элементов в вашем наборе данных неверен, поскольку он находится вне диапазона, вам все равно нужно обработать его, используя поле, достаточно большое для хранения значения.   -  person Matt Burland    schedule 07.01.2015
comment
Я сделал Id строкой, убрал конвертацию в int и вуаля! Синие птицы счастья вернулись на свое место.   -  person B. Clay Shannon    schedule 07.01.2015


Ответы (2)


Вот почему большинство программистов заканчивают тем, что используют методы расширения, а не LINQ. Переписать как:

private static SiteQuery ParseSiteQuery(XElement sitequery)
{
  return new SiteQuery
  {
      Id = Convert.ToInt32(sitequery.Element("Id").Value),
      UPCPackSize = Convert.ToInt32(sitequery.Element("UPCPackSize").Value),
      UPC_Code = sitequery.Element("UPC_Code").Value,
      crvId = sitequery.Element("crvId").Value,
      dept = Convert.ToInt32(sitequery.Element("dept").Value),
      description = sitequery.Element("description").Value,
      openQty = Convert.ToDouble(sitequery.Element("openQty").Value),
      packSize = Convert.ToInt32(sitequery.Element("packSize").Value),
      subDept = Convert.ToInt32(sitequery.Element("subDept").Value),
      unitCost = Convert.ToDecimal(sitequery.Element("unitCost").Value),
      unitList = Convert.ToDecimal(sitequery.Element("unitList").Value),
      vendorId = sitequery.Element("vendorId").Value,
      vendorItem = sitequery.Element("vendorItem").Value,
  };
}

а затем сделать

List<SiteQuery> sitequeries = xmlDoc.Descendants("SiteQuery")
                                    .Select(ParseSiteQuery).ToList();

Теперь, когда возникает исключение, вы прерываете работу этой функции преобразования с sitequery в области видимости, что дает немедленную информацию о том, какой конкретный элемент XElement вызвал сбой.

Затем вы можете использовать выражения quickwatch, чтобы быстро узнать, какой инициализатор вызвал исключение. Или даже напишите отдельные заявления для каждого присвоения свойства.

person Ben Voigt    schedule 07.01.2015

Вот что в итоге сработало:

   private void button42_Click(object sender, EventArgs e)
   {
       ArrayList arrList = 
    FetchSiteQuery("http://localhost:21608/api/sitequery/getall/dbill/ppus/42"); 
        String omnivore = "<SiteQueries>";
        foreach (String s in arrList) //- see siteQueryData.png
        {
            omnivore += s;
        }
        omnivore += "</SiteQueries>";

        String messedUpJunk = "<ArrayOfSiteQuery xmlns:i=\"http://www.w3.org/2001/XMLSchema-
    instance\" xmlns=\"http://schemas.datacontract.org/2004/07/CStore.DomainModels.HHS\">";
        omnivore = omnivore.Replace(messedUpJunk, String.Empty);
        omnivore = omnivore.Replace("</ArrayOfSiteQuery>", String.Empty);

        XDocument xmlDoc = XDocument.Parse(omnivore);
        List<SiteQuery> sitequeries = 
    xmlDoc.Descendants("SiteQuery").Select(GetSiteQueryForXMLElement).ToList();
    }

    private static SiteQuery GetSiteQueryForXMLElement(XElement sitequery)
    {
        return new SiteQuery
        {
            Id = sitequery.Element("Id").Value,
            UPCPackSize = Convert.ToInt32(sitequery.Element("UPCPackSize").Value),
            UPC_Code = sitequery.Element("UPC_Code").Value,
            crvId = sitequery.Element("crvId").Value,
            dept = Convert.ToInt32(sitequery.Element("dept").Value),
            description = sitequery.Element("description").Value,
            openQty = Convert.ToDouble(sitequery.Element("openQty").Value),
            packSize = Convert.ToInt32(sitequery.Element("packSize").Value),
            subDept = Convert.ToInt32(sitequery.Element("subDept").Value),
            unitCost = Convert.ToDecimal(sitequery.Element("unitCost").Value),
            unitList = Convert.ToDecimal(sitequery.Element("unitList").Value),
            vendorId = sitequery.Element("vendorId").Value,
            vendorItem = sitequery.Element("vendorItem").Value,
        };
    }
person B. Clay Shannon    schedule 07.01.2015