Почему универсальный метод расширения не может быть вызван с явными универсальными аргументами? - PullRequest
0 голосов
/ 13 мая 2018

У меня есть следующий метод расширения:

Module MyModule

    <Extension()>
    Public Function MyExtension(Of T)(value As T, i As T) As Short
        Return Nothing 'omitted'
    End Function

End Module

Я могу назвать это различными способами:

Dim fake As IFoo
fake.Bar().MyExtension(1)
MyModule.MyExtension(Of Integer)(fake.Bar(), 1)

Но, кажется, невозможно вызвать его как метод расширения с явным параметром универсального типа:

fake.Bar().MyExtension(Of Integer)(1)

Есть ли способ сделать это в VB? Я могу сделать это легко в C # с этим синтаксисом:

IFoo fake = null;
fake.Bar().MyExtension<int>(1);

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Из Методы расширения (Руководство по программированию в C #) (выделение выделено):

Методы расширения позволяют вам «добавлять» методы к существующим типам без создания нового производного типа,перекомпиляция или иное изменение исходного типа.Методы расширения являются особым видом статического метода, но они вызываются так, как если бы они были методами экземпляра в расширенном типе .Для клиентского кода, написанного на C #, F # и Visual Basic, нет очевидной разницы между вызовом метода расширения и методами, которые фактически определены в типе.

Разница между C # и VB заключается винтерпретация выделенного текста выше.

Для метода расширения C # с этими подписями:

public static short MyExtension<T>(this T value, T i)
{
    return default(short);
}

public static short MyExtension2<T1, T2>(this T1 value, T2 i)
{
    return default(short);
}

Там соответствующее использование в качестве методов расширения будет выглядеть (игнорируя, что типы могут быть выведены):

SomeType v0 = null;
SomeType v1 = null;
v1.MyExtension<SomeType>(v0);
v1.MyExtension2<SomeType, int>(2);

C # просто позволяет вызывать статические методы, как если бы они были методами экземпляра, не думая о том, что они «методы экземпляра в расширенном типе».VB использовал более глубокий подход к преобразованию, чтобы подпись выглядела так, как будто это действительно метод экземпляра.

Соответствующие сигнатуры метода экземпляра будут выглядеть примерно так:

internal class SomeType
{
    public short MyExtensionInstance(SomeType i)
    {
        return default(short);
    }

    public short MyExtension2Instance<T2>(T2 i)
    {
        return default(short);
    }

}

Вызовметоды экземпляра будут выглядеть так:

SomeType v0 = new SomeType();
SomeType v1 = new SomeType();
v1.MyExtensionInstance(v0);
v1.MyExtension2Instance<int>(2);

Это именно тот синтаксис, который VB применяет для методов расширения, так как они вызываются так, как если бы они были методами экземпляра в расширенном типе .

Теперь ответим на ваш вопрос;нет никакого способа заставить VB действовать как C # в отношении этого принципиального различия в реализации.

На самом деле, я не могу понять, почему вы предпочитаете стиль C #.Указание расширенного типа является многословным и излишним.Я считаю, что это также вводит несоответствие с методами расширения, где аргумент this не является универсальным, вызывая шаблон «яйцо-куриное яйцо» (тип-метод-тип), где он не нужен и не полезен.

0 голосов
/ 14 мая 2018

Полученная вами ошибка компиляции:

Метод расширения «Открытая функция MyExtension (i как Integer) как Short», определенный в «MyModule», не является универсальным (или не имеет параметров свободного типа) и поэтому не может иметь аргументы типа

Итак, как вы можете заметить в сообщении об ошибке, сигнатура метода не имеет общих аргументов. Таким образом, VB фактически не позволяет вводить универсальный тип, как он уже определен.

С IntelliSense вы можете увидеть разницу между VB и C #.

VB
enter image description here

C #
enter image description here

Обратите внимание, что при вызове на добавочный номер не отображается универсальный для VB, но отображается для C #, что позволяет вам вводить <int>, даже если это избыточно.

Так что, если вы действительно хотите предоставить универсальный тип, метод расширения должен разрешить его, так же, как у вас есть один параметр для типа, который вы расширяете, и последующие параметры для фактических значений для передачи.

<Extension()>
Public Function MyExtension(Of T1, T2)(value As T1, i As T2) As Short
    Return Nothing 'omitted'
End Function

fake.Bar().MyExtension(Of Integer)(1) ' no compile error

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

...