C# ?? null合并运算符LINQ

时间:2012-10-02 12:10:53

标签: c# xml linq null-coalescing-operator

当我使用LINQ将XML文件解析为自定义对象时,我试图阻止使用NULL值。

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

错误消息是:

  

输入字符串的格式不正确。

如果有人知道我做错了什么,请帮助:)

编辑:一段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>

6 个答案:

答案 0 :(得分:2)

这是投掷的表达式:

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

那是因为如果元素的文本节点的实际值是String.Empty而不是null,因为空字符串不是Int32.Parse的有效格式,所以尝试的转换失败。 / p>

如果XML中的元素完全丢失,这可以按预期工作,但如果有空标记<yearnode/><yearnode></yearnode>,您将获得异常。

答案 1 :(得分:1)

您可以添加Where operator

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

答案 2 :(得分:1)

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

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

答案 3 :(得分: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中引入,如果您使用的是3.5或更早版本,请使用string.IsNullOrEmpty

g.Element("domainnode").Value - 将始终返回一个字符串

如果您希望年份为null而不是0,请使用(int?)null代替0

答案 4 :(得分: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"),
...

答案 5 :(得分:0)

你的问题是从XElement转换为int?对XElement的字符串值使用int.Parse方法,在您的情况下为String.Empty。以下结果导致相同的错误:

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

您可以通过首先将XElement强制转换为字符串并检查它是否为null或空,并且仅在不执行转换为int?时避免这种情况。为此,请替换

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

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

它不漂亮,如果字符串不合法,它仍然会抛出,但如果你可以假设元素总是一个整数或null /空,它就会起作用。