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

Why can't generic extension method be called with explicit generic arguments?

我有以下扩展方法:

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

你得到的编译错误是:

Extension method 'Public Function MyExtension(i as Integer) As Short' defined in 'MyModule' is not generic (or has no free type parameters) and so cannot have type arguments

正如您在错误消息中所看到的,方法签名没有通用参数。所以 VB 实际上并没有让你输入泛型,因为它已经确定了。

借助 IntelliSense,您实际上可以看到 VB 和 C# 之间的区别。

VB

C#

请注意,对扩展的调用如何不显示 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

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

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

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C#, F# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

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# 只允许调用静态方法,就好像它们是实例方法一样,而无需考虑 "as if they were instance methods on the extended type" 部分。 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 参数不是通用的,因为在不需要或有益的地方引入了蛋-鸡-蛋(类型-方法-类型)模式。