Search code examples
c#.netgenericsextension-methodstype-parameter

extension methods with generics - when does caller need to include type parameters?


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>>();
    }
}

Solution

  • 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.