Дополнительный универсальный параметр в универсальных методах расширения? - PullRequest
7 голосов
/ 27 февраля 2010

Я хотел бы создать метод расширения для универсального класса A, который принимает еще один универсальный тип (в этом примере TC), но я полагаю, что это возможно?

class Program
{
    static void Main(string[] args)
    {
        var a = new A<B, B>();
        a.DoIt<B>();
    }
}

static class Ext
{
    public static A<TA, TB> DoIt<TA, TB, TC>(this A<TA, TB> a)
    {
        return a;
    }
}

class A<TA, TB> { }
class B { }

Ответы [ 3 ]

4 голосов
/ 27 февраля 2010

Если вы можете принять небольшое изменение синтаксиса, то это будет возможно.

Измените его на:

var a = new A<B, B>(); 
a.Do().It<B>(); 

Хитрость в том, что метод Do является методом расширения для A<TA, TB>:

public static Doer<TA, TB> Do<TA, TB>(this A<TA, TB> a)
{
    return new Doer<TA, TB>(a);
}

Хитрость заключается в том, что эта сигнатура позволяет набирающим символы набирать TA и TB с a, так что вам не нужно указывать их явно.

Класс Doer предоставляет универсальный метод, который вам нужен:

public class Doer<TA, TB>
{
    public void It<TC>() { }
}
3 голосов
/ 27 февраля 2010

Нет, это возможно, но вы должны дать компилятору некоторый приемлемый контекст того, что такое "TC". Этот третий параметр, TC, больше нигде не используется в вашем коде, поэтому он может быть чем угодно, поэтому компилятор жалуется. Однако, если вы добавляете входящий параметр в свой метод расширения типа TC, вы можете выполнить ситуацию, когда компилятор может определить фактический тип TC, и тогда вам даже не нужно будет указывать, что это за типы при вызове метод:

class Program
{
    static void Main(string[] args)
    {
        var a = new A<B, B>();
        string tc = "Hi!";
        a.DoIt(tc);
    }
}

static class Ext
{
    public static A<TA, TB> DoIt<TA, TB, TC>(this A<TA, TB> a, TC c)
    {
        return a;
    }
}

class A<TA, TB> { }
class B { }

Но вы должны дать компилятору некоторый контекст.

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

1 голос
/ 27 февраля 2010

Ты прав, это невозможно. Вы должны либо указать все параметры типа (TA, TB и TC), либо ни один из них (и оставить это до вывода типа компилятора).

Пара возможностей:

  • Превратить DoIt в метод экземпляра (хотя я думаю, что вы специально сделали его методом расширения)
  • Добавить еще один параметр в DoIt, который каким-то образом ограничивает TC, то есть вывод типа будет работать

В качестве примера второго взгляните на Enumerable.Select: у него есть два параметра типа для типов источника и назначения, но они оба выводятся из аргументов, передаваемых Select.

...