In an extension method how do a create an object based on the implementation class
In an extension method how do a create an object based on the implementation class. So in the code below I wanted to add an "AddRelationship" extension method, however I'm not sure how within the extension method I can create an Relationship object? i.e. don't want to tie the extension method to this particular implementation of 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>>();
}
}
thanks
You could add an extra type parameter representing the relationship implementation class, specifying the constraints that it must be an IRelationship
and have a parameterless constructor:
public static bool AddRelationship<T,R>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
where R : IRelationship, new() {
var rel = new R();
// ...
}
Then you should call it like this to specify the IRelationship concrete type (the 'R' type parameter):
topology.AddRelationship<string, RelationshipImp>(parentNode, childNode);
EDIT: alternative approach, without extension method: you define (and later instantiate) a RelationshipFactory class:
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();
// ...
}
}
One way would be to push the responsibility to the ITopology<T>
or INode<T>
classes by modifying their interfaces to support an IRelationship<T>
factory method, e.g. ITopology<T>
could be modified as such:
public interface ITopology<T>
{
IRleationship<T> CreateRelationship(INode<T> parent, INode<T> child);
Dictionary<T, INode<T> > Nodes { get; set; }
}
And then AddRelationship<T>
would look something like:
public static bool AddRelationship<T>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
{
var relationship = topIf->CreateRelationship(parentNode, childNode);
// ...
}
Since you're using extension methods, modifying the interfaces might not be possible or desired, but it's an option.
Addressing another (possible) problem about your design. Why are you using extension methods when you could simply put the AddRelationship method within your Topology implementation? Is there a specific need to use Extension Methods in this case? Also, is there ever going to be a case where a single node can have many parents?
I'd think something like this would be in order:
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);
}
}
No need for extension methods, or the intermediate IRelationship class. This all hinges on the ability to modify the interface for one, and that an INode can only have one parent.
Edit (Based on Comment from OP):
Considering that you're specifically after making the API for the extension method looking cleaner, you could perhaps do this:
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
}
And then calling this would be:
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));
I haven't tested this, so I may be off with where the generics are specified. I don't know if the inference engine can deduce what it needs to here.
As a point of interest, why did you decide to go with a "node has many parents and many children" instead of "node has neighbours"? I've recently built a graph structure and I found a Dictionary or List of Nodes more than adequate for modeling the directions. Just reading over the original question again - are the relationships supposed to be stored in the Topology? That'd make a lot more sense, and is what it seems you're trying to do with your original extension method.
In the case where the relationships reside in the Topology then I'd go with the other answer posted:
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);
}
And calling this:
ITopology<String> top = new TopologyImp<String>;
top.AddRelationship<RelationshipImp>(new NodeImp("parent"), new NodeImp("Child"));
精彩评论