Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用LINQ的不同字典_C#_Xml_Linq_Linq To Xml - Fatal编程技术网

C# 使用LINQ的不同字典

C# 使用LINQ的不同字典,c#,xml,linq,linq-to-xml,C#,Xml,Linq,Linq To Xml,我正在尝试使用LINQ获取不同值的字典。 我试过使用这个: var roleRefList = xDocument.Root.Descendants() .Where(x => x.Name.LocalName.Equals("roleRef") && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault

我正在尝试使用LINQ获取不同值的字典。 我试过使用这个:

var roleRefList = 
    xDocument.Root.Descendants()
             .Where(x => x.Name.LocalName.Equals("roleRef") && 
                         !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")))) && 
                         !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")))))
             .Select(l => new {
                  roleUri = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")).Value,
                  href = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")).Value
              })
             .Distinct()
             .ToDictionary(a => a.roleUri);
这里的问题是,如果
roleUri
中存在重复条目,则会发生错误。 我正在解析XML文档并制作xElement属性的字典
roleUri
roleref
(如果它们存在于xElement中)

另一种解决方法是使用for循环:

Dictionary<string, string> roleRefList = new Dictionary<string, string>();
            foreach (XElement element in xDocument.Root.Descendants().Where(x => x.Name.LocalName.Equals("roleRef")))
            {
                string roelUri = Convert.ToString(element.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")));
                string href = Convert.ToString(element.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")));
                if (!string.IsNullOrEmpty(roelUri) && !string.IsNullOrEmpty(href) && !roleRefList.ContainsKey(roelUri))
                {
                    roleRefList.Add(roelUri, href);
                }
            }
Dictionary roleRefList=new Dictionary();
foreach(xDocument.Root.subjections()中的XElement元素,其中(x=>x.Name.LocalName.Equals(“roleRef”))
{
字符串roelUri=Convert.ToString(element.Attributes().FirstOrDefault(a=>a.Name.LocalName.Equals(“roleURI”));
string href=Convert.ToString(element.Attributes().FirstOrDefault(a=>a.Name.LocalName.Equals(“href”));
如果(!string.IsNullOrEmpty(roelUri)和&!string.IsNullOrEmpty(href)和&!roleRefList.ContainsKey(roelUri))
{
roleRefList.Add(roelUri,href);
}
}

但是我想用LINQ实现它。

您可以编写自己的
Distinct
方法,该方法将
Func
作为参数。你可以在这里找到这样的例子:

使用该方法,您应该能够编写:

var roleRefList = xDocument.Root.Descendants().Where(x => x.Name.LocalName.Equals("roleRef") && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")))) && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")))))
                           .Select(l => new
                           {
                               roleUri = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")).Value,
                               href = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")).Value
                           }).Distinct(l => l.roleUri).ToDictionary(a => a.roleUri);
更新

或者,您可以使用分组:

var roleRefList = xDocument.Root.Descendants().Where(x => x.Name.LocalName.Equals("roleRef") && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")))) && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")))))
                           .Select(l => new
                           {
                               roleUri = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")).Value,
                               href = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")).Value
                           })
                           .GroupBy(l => l.roleUri)
                           .ToDictionary(g => g.Key, g => g.FirstOrDefault());

实现这一目标的两种方法:

1)您可以使用自定义相等比较器调用distinct方法。为了实现这一点,您需要先编写一个包含roleUri和href字段的类。比如:

    public class AttributePair 
    {
      public string RoleUri {get; set;}
      public string Href {get; set;}
    }
下一步是为类编写相等比较器:

    public class AttributePairComparer : IEqualityComparer<AttributePair>
    {
        public bool Equals(AttributePair x, AttributePair y)
        {
            return x.RoleUri.Equals(y.RoleUri);
        }

        public int GetHashCode(AttributePair obj)
        {
            return obj.RoleUri.GetHashCode();
        }
    }
我同意这个解决方案相当复杂,但可以说,这是实现所需结果的经典方法

2)另一种解决方案是来自的方法。其中可以将lambda表达式作为参数传递:

 var roleRefList = xDocument.Root.Descendants().Where(x => x.Name.LocalName.Equals("roleRef") && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")))) && !string.IsNullOrEmpty(Convert.ToString(x.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")))))
                       .Select(l => new
                       {
                           roleUri = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("roleURI")).Value,
                           href = l.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("href")).Value
                       }).DistinctBy(p => p.roleUri).ToDictionary(a => a.roleUri, a => a.href);

3)C#的首席架构师安德斯·海尔斯伯格(Anders Hejlsberg)提出了使用GroupBy的解决方案。您可以阅读它

在XML中不允许重复属性。如果在
roleRef
元素中有两个
roleURI
属性,则在XDocument加载期间会出现异常:

“roleURI”是重复的属性名称。第42行,位置42

因此,实际上您的代码应该如下所示:

var xdoc = XDocument.Load("foo.xml");
XNamespace ns = "http://www.adventure-works.com"; // put your namespace here

Dictionary<string, string> roleRefList = 
   xdoc.Root.Descendants(ns + "roleRef")
       .Select(r => new {
             Uri = (string)r.Attribute("roleURI"),
             Href = (string)r.Attribute("href")
       })
       .Where(r => !String.IsNullOrEmpty(r.Uri) && !String.IsNullOrEmpty(r.Href))
       .ToDictionary(r => r.Uri, r => r.Href);
var xdoc=XDocument.Load(“foo.xml”);
XNS=”http://www.adventure-works.com"; // 将名称空间放在这里
字典角色列表=
xdoc.Root.substands(ns+“roleRef”)
.选择(r=>new{
Uri=(字符串)r.Attribute(“roleURI”),
Href=(字符串)r.Attribute(“Href”)
})
.Where(r=>!String.IsNullOrEmpty(r.Uri)和&!String.IsNullOrEmpty(r.Href))
.ToDictionary(r=>r.Uri,r=>r.Href);
结果将与for循环相同。示例xml:

<root xmlns="http://www.adventure-works.com">
  <roleRef/>
  <roleRef roleURI=""/>
  <roleRef href=""/>
  <roleRef roleURI="" href=""/>
  <roleRef roleURI="a" />
  <roleRef roleURI="" href="b"/>
  <roleRef roleURI="c" href="d"/>
</root>


如果您有工作代码,为什么要使用Linq实现此功能?使用节点本地名称的原因是什么?您的xml声明了不同的名称空间?您能展示您正在解析的xml示例吗?因此,根据您的循环:如果
roleUri
存在不止一次,您只希望字典中有它的第一个实例(及其
roleRef
)?我说得对吗?@Marteen,因为linq速度更快,所以需要它。@lazyberezovsky,如果我尝试使用名称空间,但它给了我错误。所以我使用name.Localname+1。是否可以使用g.First而不是g.FirstOrDefault?我希望该组始终至少有一个成员。是的,您可以先使用
,也可以在我指定名称空间值时使用它的给我错误,但是它与名称一起工作。localname@lokendrajayaswal若并没有名称空间,那个么保持原样(或者从代码中删除ns)。如果定义了命名空间(例如
),则创建
XNamespace ns=”http://www.adventure-works.com";。请看一下linq中的xml名称空间
<root xmlns="http://www.adventure-works.com">
  <roleRef/>
  <roleRef roleURI=""/>
  <roleRef href=""/>
  <roleRef roleURI="" href=""/>
  <roleRef roleURI="a" />
  <roleRef roleURI="" href="b"/>
  <roleRef roleURI="c" href="d"/>
</root>