2012-10-02 68 views
7

我试图防止使用LINQ将XML文件解析为自定义对象时产生NULL值。C#? null合并运算符LINQ

我发现Scott Gu's blog为这个伟大的解决方案,但由于某些原因,它不与我整数的工作。我想我已经使用了相同的语法,但似乎我缺少一些东西。哦,并且由于某种原因,当节点不是空的时候它就起作用。

下面是我的代码的提取物。

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") 
     select new GrantAgresso() 
     { 
      Year = (int?)g.Element("yearnode") ?? 0, 
      Subdomain = (string)g.Element("domainnode") ?? "" 
     }).ToList(); 

的errormessage的是:

Input string was not in a correct format.

如果任何人有一个线索,我做错了,请帮助:)

编辑:一块XML(可奇怪的名字,但它是没有选择的余地)

<Agresso> 
    <AgressoQE> 
    <r3dim_value>2012</r3dim_value> 
    <r0r0r0dim_value>L5</r0r0r0dim_value> 
    <r7_x0023_province_x0023_69_x0023_V005>0</r7_x0023_province_x0023_69_x0023_V005> 
    <r7_x0023_postal_code_x0023_68_x0023_V004 /> 
    <r7_x0023_country_x0023_67_x0023_V003>1004</r7_x0023_country_x0023_67_x0023_V003> 
    <r7_x0023_communitydistrict_x0023_70_x0023_V006>0</r7_x0023_communitydistrict_x0023_70_x0023_V006> 
    </AgressoQE> 
</Agresso> 
+1

我的选择是不正确的XML语法。你能显示xml内容吗? coalesce运算符是对的,如果不是,它不会抛出这个错误(它与字符串无关) –

+0

引发异常的'Year'或'Subdomain'分配是什么?你可以尝试注释其中一行来查看异常是否消失。 – Mizipzor

+0

我已将xml的一个节点添加到我的帖子中。 它是触发异常的空节点(以r7_开头)。我用来检索它的代码与我在一年中使用的代码相同。 – Nielsm

回答

1

下面的扩展方法将返回0两者如果元素不存在,该元素为空或者它包含不能解析为整数的字符串:

public static int ToInt(this XElement x, string name) 
    { 
     int value; 
     XElement e = x.Element(name); 
     if (e == null) 
      return 0; 
     else if (int.TryParse(e.Value, out value)) 
      return value; 
     else return 0; 
    } 

你可以使用这样的:

... 
Year = g.ToInt("r3dim_value"), 
... 

或者如果你愿意考虑反射的成本和接受任何值类型的默认值,你可以使用这个扩展方法:

public static T Cast<T>(this XElement x, string name) where T : struct 
{ 
    XElement e = x.Element(name); 
    if (e == null) 
     return default(T); 
    else 
    { 
     Type t = typeof(T); 
     MethodInfo mi = t.GetMethod("TryParse", 
            BindingFlags.Public | BindingFlags.Static, 
            Type.DefaultBinder, 
            new Type[] { typeof(string), 
               t.MakeByRefType() }, 
            null); 
     var paramList = new object[] { e.Value, null }; 
     mi.Invoke(null, paramList); 
     return (T)paramList[1]; //returns default(T), if couldn't parse 
    } 
} 

,并使用它:

... 
Year = g.Cast<int>("r3dim_value"), 
... 
+0

我已经使用你的第二个建议。谢谢! – Nielsm

1

您可以添加Where operator

..... 
.Where(a => ! string.IsNullOrEmpty(a)).ToList(); 
+0

什么是'a'应该在这里?你为什么要在'IEnumerable '上调用'ToList'? – Rawling

+2

这不会做OP正在做的事情。 –

+1

不,我不想过滤结果,我只是不希望我的程序在空节点出现时中断... – Nielsm

1

如果一年为空或空字符串,你会得到一个“输入字符串的不正确的格式”异常。您可以编写一个扩展方法来读取值。我没有测试下面的代码,但它可能会给你一些提示。

public static ReadAs<T>(this XElement el, T defaultValue) { 
    var v = (string)el; // cast string to see if it is empty 

    if (string.IsNullOrEmpty(v)) // test 
    return defaultValue; 

    return (T)el; // recast to our type. 
} 
2

正是这种表达其抛出:

(int?)g.Element("yearnode") 

这是因为如果该元素的文本节点的实际值是String.Empty而不是null,因为空字符串不是Int32.Parse格式无效,试图演员失败。

如果XML中的元素完全丢失,则按预期工作,但如果存在空标记<yearnode/><yearnode></yearnode>,您将得到异常。

+0

这可能是我寻找的答案。你会建议我做什么? – Nielsm

1

消息Input string was not in a correct format看起来像一个由int.parse()异常,所以它可能是你有一个yearnode用一个值(不为空),但不能成功地解析为一个整数值。

东西这样就可以解决这个问题:

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") 
    let yearNode = g.Element("yearnode") 
    select new GrantAgresso 
    { 
     Year = string.IsNullOrWhiteSpace(yearNode.Value) ? 0 : int.Parse(yearNode.Value), 
     Subdomain = g.Element("domainnode").Value 
    }).ToList(); 

几件事情需要注意:

select new GrantAgresso - 你不需要括号与对象初始默认构造函数。

string.IsNullOrWhiteSpace - 在.NET 4.0中引入,使用string.IsNullOrEmpty如果你在3。5或更早

g.Element("domainnode").Value - 总是会返回一个字符串

如果你想有一个空的年份,而不是0,使用(int?)null代替0

+0

嗨, 我只是双重和三重检查我的XML,我想要转换为int值是空或一个有效的整数。 这是我也考虑过的;-) – Nielsm

+0

我已经更新了我的答案,并提供了一个处理空容器的建议。 –

0

您的问题是从的XElement投为int?对XElement的字符串值使用int.Parse方法,在你的情况下它是String.Empty。在同一个错误的结果如下:

XElement x = new XElement("yearnode", String.Empty); 
int? a = (int?)x; // throws FormatException 

您可以先铸造的XElement字符串,并检查它是否为空或空的避免这种情况,只有当没有做强制转换为int?要做到这一点,则更换

Year = (int?)g.Element("yearnode") ?? 0, 

Year = !string.IsNullOrEmpty((string)g.Element("yearnode")) ? (int?)g.Element("yearnode") : 0, 

它不是漂亮,还是会抛出如果字符串,否则不合法的,但它的作品,如果你可以假设元素始终是一个整数或空/空。