本文旨在通过创建一棵插件树来演示条件绑定和元数据的用法。

说“插件树”也许不大妥当,因为在一般观念中,谈到插件树,我们很容易会想到 Winform/Wpf 中的菜单。举例来说,如果要在 Winform 中创建一个层级菜单,我们可以使用类似如下代码:

// Create File menu
var newMenu = new ToolStripMenuItem(); var localProjectMenu = new ToolStripMenuItem();
var remoteProjectMenu = new ToolStripMenuItem();
var openMenu = new ToolStripMenuItem();
openMenu.DropDownItems.AddRange(new ToolStripItem[] { localProjectMenu, remoteProjectMenu}); var fileMenu = new ToolStripMenuItem();
fileMenu.DropDownItems.AddRange(new ToolStripItem[] { openMenu, newMenu });
fileMenu.Size = new System.Drawing.Size(, );
fileMenu.Text = "&File"; // Create Edit menu
var undoMenu = new ToolStripMenuItem();
var redoMenu = new ToolStripMenuItem(); var editMenu = new ToolStripMenuItem();
editMenu.DropDownItems.AddRange(new ToolStripItem[] { undoMenu, redoMenu}); // Create MenuStrip
var menuStrip = new MenuStrip();
menuStrip.Items.AddRange(new ToolStripItem[] { fileMenu, editMenu});

这样创建出来,就是一个类似如下结构的菜单树:

aaarticlea/png;base64,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" alt="" />

在上述示例中,我们通过分别创建各个菜单对象(并为各个菜单指定不同的属性,例如 Text/Size),然后将这些菜单对象插入对应的上级菜单或 MenuStrip 中,最后组装成一棵菜单树。这里,菜单类型(ToolStripMenuItem/ToolStripItem 等类型)并没有增加,增加的只是菜单类型的实例数量。换句话说,此处我们是通过增加对象实例而不是对象类型的数量来实现复用。

在 My.Ioc 中,通过为相同契约 (Contract Type) 提供多个不同实现,并将这些实现分别注册到容器中,同时结合 My.Ioc 的条件绑定和元数据功能,我们也可以方便地构建起一棵树。请看下面的示例代码:

using System;
using System.Collections.Generic;
using My.Ioc; namespace TreeBuilder
{
#region Tree/Node Types public interface INode
{
string ParentName { get; set; }
string Name { get; }
IEnumerable<INode> ChildNodes { get; }
} public abstract class Node : INode
{
string _name; public string ParentName { get; set; }
public string Name
{
get
{
_name = _name ?? GetType().Name;
return _name;
}
} public virtual IEnumerable<INode> ChildNodes
{
get { return null; }
}
} #region Level 1 public class Tree
{
readonly string _name;
readonly IEnumerable<INode> _childNodes; public Tree(IEnumerable<INode> childNodes)
{
if (childNodes == null)
throw new ArgumentException();
_name = GetType().Name;
foreach (var childNode in childNodes)
childNode.ParentName = _name;
_childNodes = childNodes;
} public string Name
{
get { return _name; }
} public IEnumerable<INode> ChildNodes
{
get { return _childNodes; }
}
} #endregion #region Level 2 public abstract class CompositeNode : Node
{
readonly IEnumerable<INode> _childNodes; protected CompositeNode(IEnumerable<INode> childNodes)
{
if (childNodes == null)
throw new ArgumentException();
foreach (var childNode in childNodes)
childNode.ParentName = Name;
_childNodes = childNodes;
} public override IEnumerable<INode> ChildNodes
{
get { return _childNodes; }
}
} public class ListNode : CompositeNode
{
public ListNode(List<INode> childNodes)
: base(childNodes)
{
}
} public class ArrayNode : CompositeNode
{
public ArrayNode(INode[] childNodes)
: base(childNodes)
{
}
} #endregion #region Level 3 public class ChildNode1 : Node
{
} public class ChildNode2 : Node
{
} public class ChildNode3 : Node
{
} public class ChildNode4 : Node
{
} public class ChildNode5 : Node
{
} public class ChildNode6 : Node
{
} public class ChildNode7 : Node
{
} public class ChildNode8 : Node
{
} #endregion #endregion class Program
{
static void Main(string[] args)
{
IObjectContainer container = new ObjectContainer(false);
Register(container); // Try to get an observer
IObjectObserver<Tree> treeObserver;
if (!container.TryGetObserver(out treeObserver))
throw new InvalidOperationException(); // Resolve the tree using the observer
var tree = container.Resolve(treeObserver);
//var tree = container.Resolve<Tree>();
PrintTreeMembers(tree, ); // Add more nodes at runtime
container.Register(typeof(INode), typeof(ChildNode8))
.WhenParentMetadata((mata) => string.Equals("ArrayNode", mata));
container.Register<INode, ChildNode7>()
.WhenParentTypeIs<ListNode>(); // Commit the registrations to the registry as usual.
container.CommitRegistrations(); Console.WriteLine();
Console.WriteLine();
Console.WriteLine(); // Resolve the tree again
tree = container.Resolve(treeObserver);
//tree = container.Resolve<Tree>();
PrintTreeMembers(tree, ); Console.ReadLine();
} static void Register(IObjectContainer container)
{
container.Register<Tree>(); container.Register<INode, ArrayNode>()
.WhenParentTypeIs<Tree>()
.Set("ArrayNode");
container.Register<INode, ListNode>()
.WhenParentTypeIs<Tree>()
.Set("ListNode"); #region Inject into ArrayNode container.Register(typeof(INode), typeof(ChildNode1))
.WhenParentMetadata((mata) => string.Equals("ArrayNode", mata)); container.Register<INode, ChildNode2>()
.WhenParentTypeIs<ArrayNode>(); container.Register<INode, ChildNode3>()
.WhenParentTypeIs<ArrayNode>(); container.Register<INode, ChildNode4>()
.WhenParentTypeIs<ArrayNode>(); #endregion #region Inject into ListNode container.Register<INode, ChildNode5>()
.WhenParentTypeIs<ListNode>(); container.Register<INode, ChildNode6>()
.WhenParentTypeIs<ListNode>(); #endregion // Commit the registrations to the registry.
container.CommitRegistrations();
} static void PrintTreeMembers(Tree tree, int time)
{
if (tree == null)
throw new ArgumentException(); Console.WriteLine(time);
Console.WriteLine("================================================="); Console.WriteLine(tree.Name); // Breadth first traversal
var allNodes = new List<INode>();
if (tree.ChildNodes == null)
return;
allNodes.AddRange(tree.ChildNodes);
for (int i = ; i < allNodes.Count; i++)
{
var node = allNodes[i];
Console.WriteLine(node.ParentName + "/" + node.Name);
if (node.ChildNodes != null)
allNodes.AddRange(node.ChildNodes);
}
}
}
}

请注意,与前一种方式相比,以这种方式来构建树的思想实际上是有所不同的。从本质上来说,这是一种通过增加(派生)类型来实现复用的手段,而前一种方式是通过增加对象实例来实现复用,这一点我们前面说过了。与前一种复用相比,这种复用有一个缺点,那就是当我们将这些类型注册到容器中时,My.Ioc 会为每个派生类型生成一个注册项,而每生成一个注册项时都会附带生成并缓存一大堆中间类(比如 ObjectBuilder/Lifetime/Injector/DependencyProvider 等),这无疑会多耗用一些内存。而前一种复用方式则无此弊病,因为它只是简单增加对象实例而已,这也是我在本文开头时说“不大妥当”的原因。

尽管如此,恰如我们在文章开头提到的,我们的目的是阐述条件绑定和元数据的用法,通过这个示例,我们达到了这个目的。至于如何更好地使用条件绑定和元数据的功能,留给各位自己去发挥好了。

源码可在此处下载,压缩包中包含了 My.Ioc 框架的源码和本示例以及其他一些示例的源码。

04-27 06:53