在扩展方法中,如何基于实现类创建对象

时间:2010-05-10 07:15:42

标签: c# .net extension-methods

在扩展方法中,如何基于实现类创建对象。所以在下面的代码中我想添加一个“AddRelationship”扩展方法,但是我不确定在扩展方法中我如何创建一个Relationship对象?即不想将扩展方法与这种特定的关系实现联系起来

   public static class TopologyExtns
    {

        public static void AddNode<T>(this ITopology<T> topIf, INode<T> node)
        {
            topIf.Nodes.Add(node.Key, node);
        }

        public static INode<T> FindNode<T>(this ITopology<T> topIf, T searchKey)
        {
            return topIf.Nodes[searchKey];
        }

        public static bool AddRelationship<T>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
        {
            var rel = new RelationshipImp();  // ** How do I create an object from teh implementation 
            // Add nodes to Relationship
            // Add relationships to Nodes
        }
    }


    public interface ITopology<T>
    {
        //List<INode> Nodes { get; set; }
        Dictionary<T, INode<T> > Nodes { get; set; }
    }

    public interface INode<T> 
    {
        // Properties
        List<IRelationship<T>> Relationships { get; set; }
        T Key { get; }
    }

    public interface IRelationship<T>
    {
        // Parameters
        INode<T> Parent { get; set; }
        INode<T> Child { get; set; }
    }


namespace TopologyLibrary_Client
{

    class RelationshipsImp : IRelationship<string>
    {
        public INode<string> Parent { get; set; }
        public INode<string> Child { get; set; }
    }
}

    public class TopologyImp<T> : ITopology<T>
    {
        public Dictionary<T, INode<T>> Nodes { get; set; }
        public TopologyImp()
        {
            Nodes = new Dictionary<T, INode<T>>();
        }

    }

感谢

3 个答案:

答案 0 :(得分:2)

您可以添加一个额外的类型参数来表示关系实现类,指定它必须是IRelationship的约束并且具有无参数构造函数:

public static bool AddRelationship<T,R>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode) 
    where R : IRelationship, new() {
    var rel = new R();
    // ...
}

然后你应该像这样调用它来指定IRelationship具体类型('R'类型参数):

topology.AddRelationship<string, RelationshipImp>(parentNode, childNode);

编辑:替代方法,没有扩展方法:您定义(并稍后实例化)RelationshipFactory类:

class RelationshipFactory<R> 
    where R : IRelationship, new(){
    // no longer an extension method:
    public static bool AddRelationship<T>(ITopology<T> topIf, INode<T> parentNode, INode<T> childNode) {
        var rel = new R();
        // ...
    }
}

答案 1 :(得分:1)

一种方法是将责任推送到ITopology<T>INode<T>类,方法是修改其接口以支持IRelationship<T>工厂方法,例如ITopology<T>可以修改为:

public interface ITopology<T>
{
    IRleationship<T> CreateRelationship(INode<T> parent, INode<T> child);
    Dictionary<T, INode<T> > Nodes { get; set; }
}

然后AddRelationship<T>看起来像:

public static bool AddRelationship<T>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
{
    var relationship = topIf->CreateRelationship(parentNode, childNode);
    // ...
}

由于您正在使用扩展方法,因此可能无法或不希望修改接口,但这是一个选项。

答案 2 :(得分:1)

解决有关您的设计的另一个(可能的)问题。当您只需将AddRelationship方法放在拓扑实现中时,为什么要使用扩展方法?在这种情况下是否有特定需要使用扩展方法?此外,是否会出现单个节点可能有多个父节点的情况?

我认为这样的事情会按顺序进行:

public interface INode<T> 
{
    // Properties
    INode<T> Parent { get; }
    IEnumerable<INode<T>> Children { get; }
    String Key { get; }

    void AddChild(INode<T> child);
}

public class Node<T> : INode<T>
{
    public Node(String key) : this(key, null) {}
    public Node(String key, INode<T> parent)
    {
        this.Parent = parent;
        this.Children = new List<T>();
        this.Key = key; 
    }

    public virtual INode<T> Parent { get; protected set; }
    public virtual String Key { get; protected set; }
    public virtual List<T> Children { get; protected set; }

    public void AddChild(INode<T> node) 
    {
        this.Children.Add(node);
    }
}

无需扩展方法或中间I​​Relationship类。这一切都取决于修改接口的能力,并且INode只能有一个父接口。

编辑(根据OP的评论):

考虑到您在使扩展方法的API看起来更干净之后,您可能会这样做:

public static bool AddRelationship(this INode<T> node, IRelationship<T> relationship) 
{
    if (node.Relationships == null)
        node.Relationships = new List<T>;

    if (relationship == null) throw new ArgumentNullException("relationship");

    node.Relationships.Add(relationship);
    return true; // I'd make this method void
}

然后调用它将是:

INode node = new Node<String>("some key");
INode someParent = new Node<String>("some parent key");
INode someChild = new Node<String>("some child key");

node.AddRelationship(new RelationshipImp(someParent, someChild));

我没有测试过这个,所以我可能会关注指定泛型的地方。我不知道推理引擎是否可以推断出它需要的东西。

作为一个兴趣点,为什么你决定选择“节点有很多父母和许多孩子”而不是“节点有邻居”?我最近构建了一个图形结构,我发现一个字典或节点列表足以对方向进行建模。只是再次阅读原始问题 - 关系应该存储在拓扑中吗?这会更有意义,而且你似乎正在尝试使用原始的扩展方法。

如果关系存在于拓扑中,那么我会选择其他答案:

public static bool AddRelationship<T,R>(this ITopology<T> top, INode<T> parent, INode<T> child ) where R : IRelationship, new
{
    IRelationship<T> rel = new R();
    rel.Parent = parent;
    rel.Child = child;
    top.Relationships.Add(rel);
}

并称之为:

ITopology<String> top = new TopologyImp<String>;
top.AddRelationship<RelationshipImp>(new NodeImp("parent"), new NodeImp("Child"));