Why can't VB.Net find an extension method on an interface?

只谈情不闲聊 提交于 2019-12-05 12:30:42

With Option Infer Off, this code...

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

...is the same as...

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

Since something is of type Object, it can't find the extension method, since it isn't defined on type Object.

Now, if you set Option Infer On, you will get the same results as with C#'s var keyword. Types will be automatically inferred. Note that this could also break existing code, but it can be enabled for a specific file, like Option Strict.

The best practice would be to set both Option Strict and Option Infer to On.

If it's throwing an exception rather than giving a compile-time error, that suggests you've got Option Strict off... I don't know what happens to extension methods in that case, as they're normally resolved at compile time, but with Option Strict off you've got late binding going on.

I suggest you turn Option Strict on, and all should be well...

(You'll also need to import the namespace, as per Richard's answer, but I'd assumed you'd already done that. You'll see a compile-time error if you forget to do that after turning option strict on, anyway.)

Cheers to Jon for pointing me in the right direction, but there's enough here to need a whole answer.

Extension methods are a compiler trick, so (in C#):

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

Is converted at compile time to be:

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

The static extension method appearing as a method of the class is just compiler cleverness.

The problem is that Dim in VB is not the same as var in C#. Thank's to VB's late binding it's closer to dynamic.

So with the original example in VB:

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

Unlike C#, in VB figuring out the type of something is left until run time, and the compiler cleverness that makes the extension methods work doesn't happen. If the type is explicitly declared the extension method can be resolved, but if late-bound then extension methods just can't ever work.

If they use Option Strict On (like Jon suggests) then they're forced to always declare the type, early-binding happens and the compiler cleverness makes the extension methods work. It's best practice anyway, but as they haven't been doing so it would be a painful change for them to make.

The moral of this story: don't use extension methods in your API if you expect anyone from VB land near it :-S

Have you imported the namespace containing the class that defines the namespace.

Eg. you won't see any of the LINQ to Objects extension methods without a

Imports System.Linq
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!