5

我有一个具有扩展方法的 C# 库,例如:

public interface ISomething { ... }
public class SomethingA : ISomething { ... }
public class SomethingB : ISomething { ... }

public static class SomethingExtensions 
{
    public static int ExtensionMethod(this ISomething input, string extra) 
    {
    }
}

如果从 C# 调用该扩展可以正常工作,但如果从外部 VB.Net 应用程序调用则会出现问题:

Dim something = Me.SomethingManager.GetSomething(key)
Dim result = something.ExtensionMethod("extra")

这编译得很好,但在运行时抛出异常:

未找到类型“SomethingB”的公共成员“ExtensionMethod”。

如果将 VB.Net 更改为显式使该类型成为其工作的接口:

Dim something as ISomething = Me.SomethingManager.GetSomething(key)
Dim result = something.ExtensionMethod("extra")

为什么?为什么扩展方法只作用于接口而不作用于实现它的类?如果我使用子类,我会遇到同样的问题吗?VB.Net 的扩展方法实现不完整吗?

我可以在 C# 库中做些什么来使 VB.Net 在没有显式接口的情况下工作吗?

4

4 回答 4

5

使用 Option Infer Off 时,此代码...

Dim something = Me.SomethingManager.GetSomething(key)
Dim result = something.ExtensionMethod("extra")

...是相同的...

Dim something As Object = Me.SomethingManager.GetSomething(key)
Dim result As Object = something.ExtensionMethod("extra")

由于somethingis 的 type Object,它找不到扩展方法,因为它没有在 type 上定义Object

现在,如果您设置,您将获得与使用 C#关键字Option Infer On相同的结果。var类型将被自动推断。请注意,这也可能会破坏现有代码,但可以为特定文件启用它,例如Option Strict.

最佳做法是将两者都设置Option StrictOption Infer开。

于 2012-05-31T13:11:19.370 回答
1

如果它抛出异常而不是给出编译时错误,则表明您已关闭Option Strict ...我不知道在这种情况下扩展方法会发生什么,因为它们通常在编译时解决,但是在 Option Strict 关闭的情况下,您将进行后期绑定。

我建议你打开 Option Strict,一切都应该很好......

(根据理查德的回答,您需要导入命名空间,但我假设您已经这样做了。如果您在打开选项严格后忘记这样做,您会看到编译时错误,无论如何.)

于 2012-05-31T08:06:30.650 回答
1

为 Jon 为我指明正确的方向而欢呼,但这里需要一个完整的答案就足够了。

扩展方法是一种编译器技巧,因此(在 C# 中):

var something = this.SomethingManager.GetSomething(key);
var result = something.ExtensionMethod("extra");

在编译时转换为:

ISomething something = this.SomethingManager.GetSomething(key);
int result = SomethingExtensions.ExtensionMethod(something, "extra");

作为类的方法出现的静态扩展方法只是编译器的聪明之处。

问题是Dim在 VB 中与var在 C# 中不同。感谢 VB 的后期绑定,它更接近dynamic.

因此,使用 VB 中的原始示例:

Dim something = Me.SomethingManager.GetSomething(key)
Dim result = something.ExtensionMethod("extra")

与 C# 不同,在 VB 中确定类型的工作something要等到运行时才进行,并且不会发生使扩展方法起作用的编译器的聪明才智。如果显式声明了类型,则可以解析扩展方法,但如果是后期绑定,则扩展方法将永远无法工作。

如果他们使用Option Strict On(如 Jon 建议的那样),那么他们将被迫总是声明类型,发生早期绑定并且编译器的聪明才智使扩展方法起作用。无论如何,这是最佳实践,但由于他们没有这样做,因此做出的改变对他们来说将是一个痛苦的改变。

这个故事的寓意:如果您希望任何来自 VB 的人在它附近登陆,请不要在您的 API 中使用扩展方法:-S

于 2012-05-31T11:13:45.060 回答
0

您是否导入了包含定义命名空间的类的命名空间。

例如。如果没有

Imports System.Linq
于 2012-05-31T08:06:22.743 回答