Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a C# library that has an extension method, something like:

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

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

The extension works fine if called from C#, but has an issue if called from an external VB.Net application:

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

This compiles fine but throws an exception at run time:

Public member 'ExtensionMethod' on type 'SomethingB' not found.

If the VB.Net is changed to explicitly make the type the interface it works:

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

Why? Why does the extension method work on the interface but not the class that implements it? Would I have the same issue if I used a subclass? Is VB.Net's implementation of extension methods incomplete?

Is there anything I can do in the C# library to make VB.Net work without the explicit interface?

like image 216
Keith Avatar asked May 31 '12 08:05

Keith


3 Answers

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.

like image 101
Meta-Knight Avatar answered Nov 15 '22 07:11

Meta-Knight


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

like image 40
Jon Skeet Avatar answered Nov 15 '22 08:11

Jon Skeet


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

like image 23
Keith Avatar answered Nov 15 '22 07:11

Keith