How can I determine which element is causing an ov

2019-09-17 06:27发布

问题:

I've got this code:

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

testData is:

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

But I get the following runtime exception with this code and data:

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: 

There are several int values (4) in each xml "record"; there are thousands of records. How can I, without trying to put on a Rainman hat (which doesn't fit me very well) determine just which value is the problematic one causing the overflow or underflow?

If it's an underflow (the exception msg says both "OverflowException" and "Value was either too large or too small for an Int32", could it be cause by an empty value for one of those four int members? If so, how can I tell it to consider an empty value as 0?

回答1:

This is why most coders end up using extension methods, but not LINQ. Rewrite as:

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

and then do

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

Now when the exception occurs, you'll break inside this conversion function, with sitequery in scope, giving immediate knowledge of what particular XElement caused the failure.

Then you can use quickwatch expressions to quickly find out what initializer caused the exception. Or even write separate statements for each property assignment.



回答2:

This is what ended up working:

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