методы расширения с обобщениями - когда вызывающей стороне нужно включать параметры типа? - PullRequest
0 голосов
/ 10 мая 2010

Существует ли правило для того, чтобы знать, когда нужно передавать параметры универсального типа в коде клиента при вызове метода расширения?

Так, например, в классе Program, почему я (а) не могу передать параметры типа для top.AddNode (узла), но где, как позже для строки (b) top.AddRelationship, я должен передать их?

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

Ответы [ 4 ]

10 голосов
/ 10 мая 2010

Что касается второго примера, компилятор не знает, какой тип вы хотите для R; он только знает, что должен реализовывать IRelationship<T> и иметь открытый конструктор по умолчанию. Он не может вывести его из параметров, которые вы передаете методу, потому что они относятся к типу T. В этом случае вам нужно указать, какой класс вы хотите использовать для R. Если вы хотите передать, вместо этого Если создать экземпляр R, то в качестве аргумента он сможет вывести тип, и вам не нужно будет его предоставлять.

В первом случае вам не нужно указывать типы, потому что аргументы относятся к типу, и поэтому компилятор может вывести типы, которые вы имеете в виду.

1 голос
/ 10 мая 2010

Как правило, вам не нужно явно указывать тип. Вам это нужно, когда тип фактически является аргументом - и примером этому является функция linq .Cast - ее тип говорит ему, что делать: Cast<Employee>()

В вашем случае это довольно просто: AddRelationship<T,R> имеет три аргумента, все типа T - как можно R сделать вывод?

0 голосов
/ 10 мая 2010

Я думаю, это потому, что вы не включили в функцию аргументы с типом R.

0 голосов
/ 10 мая 2010

Я не выполнил эту конкретную настройку, но я понимаю, что вывод типа состоит в том, что вызывающей стороне не нужно указывать тип. это ITopology<T> topIf будет ссылаться на экземпляр, в котором тип уже объявлен. Метод расширения должен неявно принимать тот же параметр типа.

Многие методы расширения LINQ основаны на общих методах расширения IEnumerable. Это тот же шаблон, который вы используете. Это хорошее место, чтобы начать искать.

И как всегда, тест.

...