Почему VB.Net не может найти метод расширения интерфейса?

У меня есть библиотека 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")

Это прекрасно компилируется, но выдает исключение во время выполнения:

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

Если VB.Net изменяется, чтобы явно сделать тип интерфейсом, на котором он работает:

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

Зачем? Почему метод расширения работает с интерфейсом, а не с классом, который его реализует? У меня была бы та же самая проблема, если бы я использовал подкласс? Является ли реализация расширенных методов в VB.Net неполной?

Что я могу сделать в библиотеке C #, чтобы VB.Net работал без явного интерфейса?

Ответы на вопрос(4)

Вы импортировали пространство имен, содержащее класс, который определяет пространство имен.

Например. вы не увидите ни одного из методов расширения LINQ to Objects без

Imports System.Linq
 Keith31 мая 2012 г., 10:10
Как я объяснил в вопросе, метод работает, если интерфейс явно объявлен. Ошибка во время выполнения, а не во время компиляции.

Если этоthrowing an exception вместо того, чтобы выдавать ошибку во время компиляции, это говорит о том, что вы получилиВариант Строгий off ... Я не знаю, что происходит с методами расширения в этом случае, так как они обычно разрешаются вcompile time, но с опцией Option Strict вы связываетесь поздно.

Я предлагаю вам включить Option Strict, и все должно быть хорошо ...

(Вы & APOS; LLalso Мне нужно импортировать пространство имен, согласно ответу Ричарда, но я предположил, что вы это уже сделали. Вы увидитеcompile-time ошибка, если вы забудете сделать это после включения опции строго в любом случае.)

 Keith31 мая 2012 г., 10:40
К сожалению, у меня нет такой опции - у них уже есть много кода VB.Net, который имеетOption Strict Off, Они получают множество ошибок компиляции, если они включают его сейчас. Означает ли это, что методы расширения не могут работать сany переменные с поздней привязкой в VB.Net?
 31 мая 2012 г., 14:13
@Keith Вы можете установитьOption Strict On на каждом отдельном файле кода. Просто добавьте строкуOption Strict On в начало файла, прежде чем что-либо еще. Вам не нужно включать его для всего проекта. Это МОЖЕТ быть очень сложным, если делать это в устаревшем коде.
 Keith31 мая 2012 г., 11:28
Да, поворачиваясьOption Strict On просто генерирует исключения времени компиляции, когда у них нетas ISomething - они хотят иметь позднюю привязку и метод расширения. Они хотятDim в VB вести себя какvar делает в C #. Я думаю, что это просто не может произойти.

Приветствую Джона за то, что он указал мне правильное направление, но здесь достаточно, чтобы нужен полный ответ.

Методы расширения являются трюком компилятора, поэтому (в 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 (как предлагает Джон), тогда они вынуждены всегда объявлять тип, происходит раннее связывание, и хитрость компилятора заставляет работать методы расширения. В любом случае, это лучшая практика, но, поскольку они этого не делали, это было бы болезненным изменением для них.

Мораль этой истории: не используйте методы расширения в своем API, если вы ожидаете, что кто-нибудь из VB окажется рядом с ним: -S

 31 мая 2012 г., 15:12
Вы можете получить те же результаты, что и в C #, установивOption Infer On, Смотри мой ответ.
Решение Вопроса

С опцией 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 Strict а такжеOption Infer вкл.

 01 июн. 2012 г., 10:17
@Keith: Эта боль преобразования, вероятно,good вещь в долгосрочной перспективе. Я очень рекомендую вам использовать Option Strict везде, где это возможно.
 Keith31 мая 2012 г., 18:40
Я не думаюOption Infer установлен в любом случае, и я думаю, что по умолчаниюOn - Я должен это проверить.
 Keith01 июн. 2012 г., 10:12
Ах, да, если вы не укажете опцию логического вывода, Visual Studio по умолчанию включен, но компиляторы командной строки по умолчанию выключены.Option Infer On последовательно решает эту проблему с нагрузками меньшими, чемOption Strict.
 Keith01 июн. 2012 г., 10:25
@JonSkeet: Я полностью согласен, но это болезненный вариант для ретро-подгонки.Option Strict On безусловно, лучшая практика.Option Infer On исправили это для ребят из VB.Net без необходимости менять загрузку кода.

Ваш ответ на вопрос