C# C零合并算子LINQ

C# C零合并算子LINQ,c#,xml,linq,null-coalescing-operator,C#,Xml,Linq,Null Coalescing Operator,在使用LINQ将XML文件解析为自定义对象时,我试图防止出现空值 我在上找到了一个很好的解决方案,但由于某些原因,它对整数不起作用。我想我使用了相同的语法,但似乎我遗漏了一些东西。哦,由于某种原因,当节点不为空时,它会工作 下面是我的代码摘录 List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") select new GrantAgresso()

在使用LINQ将XML文件解析为自定义对象时,我试图防止出现空值

我在上找到了一个很好的解决方案,但由于某些原因,它对整数不起作用。我想我使用了相同的语法,但似乎我遗漏了一些东西。哦,由于某种原因,当节点不为空时,它会工作

下面是我的代码摘录

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>
您可以添加Where操作符

若年份为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.
}

正是这句话引发了:

(int?)g.Element("yearnode")
这是因为,如果元素的文本节点的实际值为String.Empty且不为null,则由于空字符串不是Int32.Parse的有效格式,因此尝试的强制转换将失败

如果XML中完全缺少该元素,这将如您所期望的那样工作,但如果存在空标记或,则会出现异常

消息输入字符串的格式与int.parse抛出的格式不正确,因此可能是您有一个值不为null但无法成功解析为整数值的DearhNode

像这样的事情可能会解决它:

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();
有几件事需要注意:

选择new GrantAgresso-对于具有对象初始值设定项的默认构造函数,不需要括号

string.IsNullOrWhiteSpace-是在.net 4.0中引入的,如果您使用的是3.5或更早版本,请使用string.IsNullOrEmpty

g、 Elementdomainnode.Value-将始终返回字符串


如果您希望年为null而不是0,请使用int?null而不是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,


它并不漂亮,如果字符串不合法,它仍将抛出,但如果您可以假定元素始终为整数或null/空,则它可以工作。

如果元素不存在、元素为空或它包含无法解析为整数的字符串,则以下扩展方法将返回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"),
...

我打赌xml语法不正确。可以显示xml内容吗?coalesce操作符是正确的,如果不是,它不会抛出此错误,它与抛出异常的年份或子域分配无关?您可以尝试注释其中一行,看看异常是否消失。触发异常的是以r7_开头的空节点。我用来检索它的代码和我一年来使用的代码一样。a应该是什么?为什么要在看起来像IEnumerable的对象上调用ToList?这与OP试图做的不一样。不,我不能,我不想过滤结果,我只是不想在出现空节点时我的程序中断…嗨,我刚刚双重和三重检查了我的XML,我想转换为int的值要么是空的,要么是有效的整数。这是我也考虑过的,-我已经更新了我的答案,并提出了处理空瓶的建议。这可能是我一直在寻找的答案。你建议我做什么?我用了你的第二个建议。谢谢!
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"),
...