Linq查询从对象数组中获取数据c#

时间:2011-03-28 13:28:45

标签: c# arrays linq struct

public struct Parameter 
{
    public Parameter(string name, string type, string parenttype)  
    {        
        this.Name = name;
        this.Type = type;
        this.ParentType = parenttype;        
    }
    public string Name;
    public string Type;
    public string ParentType;
}

以下值存储在参数:

的数组中
Name        Type                 ParentType
-------------------------------------------------------
composite   CompositeType        
isThisTest  boolean              
BoolValue   boolean              CompositeType
StringValue string               CompositeType
AnotherType AnotherCompositeType CompositeType
account     string               AnotherCompositeType
startdate   date                 AnotherCompositeType

我想读这个来构建一个xml。类似的东西:

<composite>
    <BoolValue>boolean</BoolValue>
    <StringValue>string</StringValue>
    <AnotherType>
        <account>string</account>
        <startdate>date</startdate>
    </AnotherType>    
<composite>
<isThisTest>boolean</isThisTest>

我使用以下逻辑来读取值:

foreach (Parameter parameter in parameters)
{
    sb.Append("        <" + parameter.Name + ">");
    //HERE: need to check parenttype and get all it's child elements
    //
    sb.Append("</" + parameter.Name + ">" + CrLf);
}

是否有更简单的方法来读取数组以获取父母和他们的孩子?可能正在使用LINQ?我还在.Net 3.5上。通过示例代码感谢任何建议:)

2 个答案:

答案 0 :(得分:5)

你可以写一点递归方法来解决这个问题:

IEnumerable<XElement> GetChildren ( string rootType, List<Parameter> parameters )
{
    return from p in parameters
        where p.ParentType == rootType
        let children = GetChildren ( p.Type, parameters )
        select  children.Count() == 0 ? 
            new XElement ( p.Name, p.Type ) :
            new XElement ( p.Name, children );
}

每次调用都会构建一个XElements的Enumerable,其中包含父级具有传入类型的参数。 select再次递归到方法中,再次找到每个Element的子节点。

请注意,这确实假设数据已正确形成。如果两个参数相互作为父项,则会出现Stack Overflow。

魔法在XElements类(Linq to Xml)中,它接受XElements的可枚举来构建像Xml结构的树。

第一次调用,传递null(或使用默认参数,如果使用C#4)作为rootType。使用如下:

void Main()
{
    var parameters = new List<Parameter> {
        new Parameter {Name = "composite", Type = "CompositeType" },
        new Parameter {Name = "isThisTest", Type = "boolean" },
        new Parameter {Name = "BoolValue", Type = "boolean", ParentType = "CompositeType" },
        new Parameter {Name = "StringValue", Type = "string", ParentType = "CompositeType" },
        new Parameter {Name = "AnotherType", Type = "AnotherCompositeType", ParentType = "CompositeType" },
        new Parameter {Name = "account", Type = "string", ParentType = "AnotherCompositeType" },
        new Parameter {Name = "startdate", Type = "date", ParentType = "AnotherCompositeType" }
    };

    foreach ( var r in GetChildren ( null, parameters ) )
    {
        Console.WriteLine ( r );
    }

}

输出:

<composite>
  <BoolValue>boolean</BoolValue>
  <StringValue>string</StringValue>
  <AnotherType>
    <account>string</account>
    <startdate>date</startdate>
  </AnotherType>
</composite> 
<isThisTest>boolean</isThisTest>

修改

在回复您的评论时,XElement为您提供了两个输出字符串的选项。

ToString()将输出格式化的Xml。

ToString(SaveOptions)允许您指定格式化或未格式化的输出以及省略重复的命名空间。

我确定你可以调整解决方案以使用StringBuilder,如果你真的不得不这样做,虽然它可能不会那么优雅..

答案 1 :(得分:1)

看起来你想要使用递归方法,例如:

string GetChildren(Parameter param, string indent)
{
    StringBuilder sb = new StringBuilder();
    if (HasChildren(param))
    {
        sb.AppendFormat("{0}<{1}>{2}", indent, param.Name, Environment.NewLine);
        foreach (Parameter child in parameters.Where(p => p.ParentType == param.Type))
        {
            sb.Append(GetChildren(child, indent + "   "));
        }
        sb.AppendFormat("{0}</{1}>{2}", indent, param.Name, Environment.NewLine);
    }
    else
    {
        sb.AppendFormat("{0}<{1}>{2}</{1}>{3}", indent, param.Name, param.Type, Environment.NewLine);
    }
    return sb.ToString();
}

查看参数是否具有子节点的方法如下所示:

bool HasChildren(Parameter param)
{
    return parameters.Any(p => p.ParentType == param.Type);
}

集合parameters可以定义为IEnumerable<Parameter>,可以使用List<Parameter>来实现。