为什么VB.Net无法在接口上找到扩展方法?

时间:2012-05-31 08:03:41

标签: .net vb.net extension-methods

我有一个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 个答案:

答案 0 :(得分:4)

使用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")

由于something的类型为Object,因此无法找到扩展方法,因为它未在类型Object上定义。

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

最佳做法是将Option StrictOption Infer都设置为开启。

答案 1 :(得分:1)

如果抛出异常而不是发出编译时错误,那表明你已经关闭Option Strict ...我不知道扩展方法会发生什么变化那种情况,因为它们通常在编译时解决,但是如果Option Strict关闭,你就会有后期绑定。

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

(根据Richard的回答,你需要导入命名空间,但我认为你已经完成了。你会看到编译时< / em>错误,如果您在关闭选项严格后忘记执行此操作。无论如何。)

答案 2 :(得分:1)

为乔恩指责我指向正确的方向干杯,但这里有足够的答案需要一个完整的答案。

扩展方法是编译技巧,所以(在C#中):

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

在编译时转换为:

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

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

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

使用VB中的原始示例:

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

与C#不同,在VB中,确定something的类型将一直保留到运行时,并且编译器的灵活性使得扩展方法不起作用。如果显式声明了类型,则可以解析扩展方法,但如果是后期绑定,那么扩展方法就无法工作。

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

这个故事的寓意:如果你希望VB附近有人在你的API附近使用扩展方法:-S

答案 3 :(得分:0)

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

EG。没有

,你将看不到任何LINQ to Objects扩展方法
Imports System.Linq