如何为命名空间创建树状数据结构。
例如,对于这些名称空间:
Enums.NEWENUMS.NEW1
Enums.NEWENUMS.NEW2
Enums.NEWENUMS.NEW3
Enums.OLDENUMS
Enums.TEST.SUB
Enums.TEST.SUB.OK
然后将其加载到如下所示的树视图中:
我试图拆分名称空间,但是对于我的生活,我无法想到正确生成它的逻辑。
还尝试以生成目录结构的方式生成它,但由于名称空间需要拆分而无法理解它。
答案 0 :(得分:3)
这是表示命名空间的类。它将名称空间表示为直接嵌套名称空间的字典。要从字符串生成Namespace
,它会提供使用recursive calls和LINQ的静态方法:
public class Namespace : IDictionary<String, Namespace>
{
#region Static
public static IEnumerable<Namespace> FromStrings(IEnumerable<String> namespaceStrings)
{
// Split all strings
var splitSubNamespaces = namespaceStrings
.Select(fullNamespace =>
fullNamespace.Split('.'));
return FromSplitStrings(null, splitSubNamespaces);
}
public static IEnumerable<Namespace> FromSplitStrings(Namespace root, IEnumerable<IEnumerable<String>> splitSubNamespaces)
{
if (splitSubNamespaces == null)
throw new ArgumentNullException("splitSubNamespaces");
return splitSubNamespaces
// Remove those split sequences that have no elements
.Where(splitSubNamespace =>
splitSubNamespace.Any())
// Group by the outermost namespace
.GroupBy(splitNamespace =>
splitNamespace.First())
// Create Namespace for each group and prepare sequences that represent nested namespaces
.Select(group =>
new
{
Root = new Namespace(group.Key, root),
SplitSubnamespaces = group
.Select(splitNamespace =>
splitNamespace.Skip(1))
})
// Select nested namespaces with recursive split call
.Select(obj =>
new
{
Root = obj.Root,
SubNamespaces = FromSplitStrings(obj.Root, obj.SplitSubnamespaces)
})
// Select only uppermost level namespaces to return
.Select(obj =>
obj.Root)
// To avoid deferred execution problems when recursive function may not be able to create nested namespaces
.ToArray();
}
#endregion
#region Fields
private IDictionary<String, Namespace> subNamespaces;
#endregion
#region Constructors
private Namespace(String nameOnLevel, Namespace parent)
{
if (String.IsNullOrWhiteSpace(nameOnLevel))
throw new ArgumentException("nameOfLevel");
this.Parent = parent;
this.NameOnLevel = nameOnLevel;
this.subNamespaces = new Dictionary<String, Namespace>();
if (this.Parent != null)
{
this.Parent.Add(this.NameOnLevel, this);
}
}
private Namespace(String nameOfLevel)
: this(nameOfLevel, null)
{
}
#endregion
#region Properties
public String NameOnLevel
{
get;
private set;
}
public String FullName
{
get
{
if (this.Parent == null)
return this.NameOnLevel;
return String.Format("{0}.{1}",
this.Parent.FullName,
this.NameOnLevel);
}
}
private Namespace _Parent;
public Namespace Parent
{
get
{
return this._Parent;
}
private set
{
if (this.Parent != null)
this.Parent.Remove(this.NameOnLevel);
this._Parent = value;
}
}
#endregion
#region IDictionary implementation
public void Add(string key, Namespace value)
{
if (this.ContainsKey(key))
throw new InvalidOperationException("Namespace already contains namespace with such name on level");
this.subNamespaces.Add(key, value);
}
public bool ContainsKey(string key)
{
return this.subNamespaces.ContainsKey(key);
}
public ICollection<string> Keys
{
get { return this.subNamespaces.Keys; }
}
public bool Remove(string key)
{
if (!this.ContainsKey(key))
throw new KeyNotFoundException();
this[key]._Parent = null;
return this.subNamespaces.Remove(key);
}
public bool TryGetValue(string key, out Namespace value)
{
return this.subNamespaces.TryGetValue(key, out value);
}
public ICollection<Namespace> Values
{
get { return this.subNamespaces.Values; }
}
public ICollection<Namespace> Subnamespaces
{
get { return this.subNamespaces.Values; }
}
public Namespace this[string nameOnLevel]
{
get
{
return this.subNamespaces[nameOnLevel];
}
set
{
if (value == null)
throw new ArgumentException("value");
Namespace toReplace;
if (this.TryGetValue(nameOnLevel, out toReplace))
{
toReplace.Parent = null;
}
value.Parent = this;
}
}
public void Add(KeyValuePair<string, Namespace> item)
{
this.Add(item.Key, item.Value);
}
public void Clear()
{
foreach (var subNamespace in this.subNamespaces.Select(kv => kv.Value))
{
subNamespace._Parent = null;
}
this.subNamespaces.Clear();
}
public bool Contains(KeyValuePair<string, Namespace> item)
{
return this.subNamespaces.Contains(item);
}
public void CopyTo(KeyValuePair<string, Namespace>[] array, int arrayIndex)
{
this.subNamespaces.CopyTo(array, arrayIndex);
}
public int Count
{
get { return this.subNamespaces.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<string, Namespace> item)
{
return this.subNamespaces.Remove(item);
}
public IEnumerator<KeyValuePair<string, Namespace>> GetEnumerator()
{
return this.subNamespaces.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region Overrides
public override string ToString()
{
return this.FullName;
}
#endregion
}
P.S:此类可能很少有错误实现的方法。
P.S.1:可以在没有LINQ的情况下重写解析方法。实际上,这个LINQ解决方案不是非常惯用,也不是一个如何以及何时使用LINQ的非常好的例子。但它很简短,而且很简单。
您还没有提到您使用的UI框架,因此我默认使用了Windows窗体。假设您已将名为treeView_Namespaces
的TreeView添加到表单中:
public Form1()
{
InitializeComponent();
var namespaceStrings = new String[]
{
"Enums.NEWENUMS.NEW1",
"Enums.NEWENUMS.NEW2",
"Enums.NEWENUMS.NEW3",
"Enums.OLDENUMS",
"Enums.TEST.SUB",
"Enums.TEST.SUB.OK"
};
var namespaces = Namespace.FromStrings(namespaceStrings);
AddNamespaces(this.treeView_Namespaces.Nodes, namespaces);
}
void AddNamespaces(TreeNodeCollection nodeCollection, IEnumerable<Namespace> namespaces)
{
foreach (var aNamespace in namespaces)
{
TreeNode node = new TreeNode(aNamespace.NameOnLevel);
nodeCollection.Add(node);
AddNamespaces(node.Nodes, aNamespace.Subnamespaces);
node.Expand();
}
}
要做到这一点,你必须浏览Assembly中的类型并获取所有名称空间:
例如,此代码获取当前正在执行的程序集中的所有类型:
var namespaceStrings = Assembly
.GetExecutingAssembly()
.GetTypes()
.Select(type =>
type.Namespace)
.Where(@namespace =>
@namespace != null);