views:

78

answers:

4

Hi,

Is there a rule for knowing when one has to pass the generic type parameters in the client code when calling an extension method?

So for example in the Program class why can I (a) not pass type parameters for top.AddNode(node), but where as later for the (b) top.AddRelationship line I have to pass them?

class Program
{
    static void Main(string[] args)
    {
        // Create Graph
        var top = new TopologyImp<string>();

        // Add Node
        var node = new StringNode();
        node.Name = "asdf";
        var node2 = new StringNode();
        node2.Name = "test child";
        top.AddNode(node);
        top.AddNode(node2);


        top.AddRelationship<string, RelationshipsImp>(node,node2);  // *** HERE ***

    }
}


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 void AddRelationship<T,R>(this ITopology<T> topIf,  INode<T> parentNode,  INode<T> childNode) 
        where R : IRelationship<T>, new()
    {
        var rel = new R();
        rel.Child = childNode;
        rel.Parent = parentNode;
    }
  }


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

I haven't done this particular setup, but my understanding of type inference is that the caller would not need to specify the type. this ITopology<T> topIf will refer to an instance in which the type is already declared. The extension method should pick up the same type parameter implicitly.

A lot of the LINQ extension methods are based on generic extension methods of IEnumerable. It's the same pattern that you're using. That's a good place to start looking.

And as always, test.

Cylon Cat
+10  A: 

With respect to the second example, the compiler does not know what type you want for R; it only knows that it must implement IRelationship<T> and have a public default constructor. It can't infer it from any of the parameters you pass to the method because they are of type T. In that case, you need to tell it what class you want to be used for R. If you were to pass in, instead of create an instance of R, as an argument, it would be able to infer the type and you wouldn't need to supply them.

In the first case, you don't need to supply the types because the arguments are of the type and thus the compiler can infer the types that you mean.

tvanfosson
Was just typing the same thing...
David M
@tvanfosson - thanks, so there's no way to provide my library to client users where the client methods provides are (a) easy to use with no requirement to specify types, and (b) based on extension methods [i.e. as opposed to abstract base class extensions] then? Seems like there not be a way?
Greg
@Greg - possibly have your Topology interface contain a (factory) method to create a relationship from two INodes. Then you can use the factory method in your extension method to create the appropriate relationship and don't need to provide the type to the method.
tvanfosson
A: 

I think it is because you do not include any argument with type R in the function.

Pablo Castilla
+1  A: 

Generally, you don't have to explicitly specify the type. You need it when the type is in fact an argument - and example to this is the linq function .Cast - it's type tells it what to do: Cast<Employee>()

In your case this is quite simple: AddRelationship<T,R> has three argumenta, all of type T - how can R be inferred?

Kobi