我有一些代码需要扫描分层数据库模式,寻找在模式中定义的具有某些有趣属性的属性。我想制作这些属性名称的(平面)列表。
为了(希望)减少混淆,我将调用模式“Kinds”中定义的类,因为模式不描述C#类层次结构。
作为.NET对象的树,我可以使用该模式;我不需要解析任何XML或任何东西。问题是我将在不同的点进入模式树,我需要确保我知道从基类继承的有趣属性以及那些直接定义的属性。我正在看。
results = new List<PropertyDefinition>;
foreach (Kind objKind in objDescription.PossibleKinds)
{
// Iterate up the schema hierarchy
while (objKind != null)
{
foreach (PropertyDefinition prop in objKind.PropertyDefinitions)
{
if (prop.IsInteresting)
results.Add(prop);
}
// Move up a level in the hierarchical relationship
objKind = objKind.BaseKind;
}
}
无论如何,我想知道是否可以编写一个等效的LINQ语句。最外层的foreach循环是微不足道的(实际上还有另一个我为了清晰而遗漏了)但我不确定是否有可能在LINQ查询中捕获层次结构中的迭代。
var query = from objKind in objDescription.PossibleKinds
// What goes here?
from prop in objKind.PropertyDescriptions
where prop.IsInteresting
select prop;
我想这类似于编写LINQ查询,该查询以链表中的节点开始,并一直迭代链表直到结束。这可能吗?
答案 0 :(得分:2)
你不能用'纯'LINQ真正做到这一点,但你可以将它与枚举器方法混合使用,你就会走上正轨。例如,在Kind
类型上定义一个扩展方法,如下所示:
public static IEnumerable<Kind> GetInstanceAndBaseKinds(
this Kind instance)
{
while (instance != null)
{
yield return instance;
instance = instance.BaseKind;
}
}
现在您可以在LINQ查询中使用此方法:
from kind in objDescription.PossibleKinds
from baseKind in kind.GetInstanceAndBaseKinds()
from property in baseKind.PropertyDefinitions
where property.IsInteresting
select property;
答案 1 :(得分:1)
Here is a post引入了一种扩展方法Descendants()
,可能会让您朝着正确的方向前进。
答案 2 :(得分:0)
你可以做一个递归的Action<Kind, List<PropertyDefinition>
:
Action<Kind, List<PropertyDefinition> action = null;
action = (k, l) => {
if (k == null) return;
foreach (var definition in k.PropertyDefinitions)
{
if (definition.IsInteresting)
l.Add(definition);
}
action(k.BaseKind, l);
};
var results = new List<PropertyDefinition>();
foreach (var kind in objDescription.PossibleKinds)
{
action(kind, results);
}
注意你需要如何将声明与动作的分配分开。希望有所帮助。
答案 3 :(得分:0)
请考虑这个建议:
使用LinqToSQL映射表'dbo.Groups',生成以下类Group
[Table(Name = "dbo.Groups")]
public partial class Group
{
[Column(Storage = "_Id", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
public int Id
{
get { return this._Id; }
set { this._Id = value; }
}
[Column(Storage = "_ParentId", DbType = "Int")]
public System.Nullable<int> ParentId
{
get { return this._ParentId; }
set { this._ParentId = value; }
}
[Association(Name = "Group_Group", Storage = "_Children", ThisKey = "Id", OtherKey = "ParentId")]
public EntitySet<Group> Children
{
get { return this._Children; }
set { this._Children.Assign(value); }
}
}
然后在LinqExtension之后添加(由how-to-get-a-tree-structured-table-data-by-linq提供)
public static class LinqExtensions
{
static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> DescendBy)
{
foreach (T value in source)
{
yield return value;
foreach (T child in DescendBy(value).Descendants<T>(DescendBy))
{
yield return child;
}
}
}
}
最后,将以下方法添加到我的Group Class:
public partial class Group
{
public IEnumerable<Group> Descendants()
{
return LinqExtensions.Descendants(Children, c => c.Children);
}
public IEnumerable<Group> Genealogy()
{
Group[] ancestor = new Group[] { this };
return ancestor.Concat(LinqExtensions.Descendants(Children, c => c.Children));
}
}
如果我理解你的问题,Genealogy方法可以帮助你。
答案 4 :(得分:0)
虽然Steven的答案可能更好,但我使用的实现是对象上的Ancestors
属性:
partial class Kind
{
public IEnumerable<Kind> Ancestors
{
get
{
for (var p = BaseKind; p != null; p = p.BaseKind)
yield return p;
}
}
public IEnumerable<Kind> ThisAndAncestors
{
get
{
for (var p = this; p != null; p = p.BaseKind)
yield return p;
}
}
}