为什么不能使用显式泛型参数调用泛型扩展方法?

时间:2018-05-13 18:22:52

标签: .net vb.net generics extension-methods

我有以下扩展方法:

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 :(得分:1)

你得到的编译错误是:

  

扩展方法'公共函数MyExtension(i as Integer)As 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

不确定你在做什么,但这仅仅是一个例子。我不太熟悉扩展方法,这只是我的观察。

答案 1 :(得分:1)

来自Extension Methods (C# Programming Guide)(强调补充):

  

扩展方法可让您添加&#34;现有类型的方法   无需创建新的派生类型,重新编译或其他方式   修改原始类型。扩展方法是一种特殊的方法   静态方法,但它们被称为就像它们是实例方法一样   扩展类型。对于用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参数不是通用的,它通过诱导一个不需要也没有益处的egg-chicken-egg(类型方法类型)模式。