Доступ к методу расширения в расширенном типе? - PullRequest
0 голосов
/ 24 января 2019

В последнее время я проводил рефакторинг старого кода, и многие методы полезны в качестве методов расширения для базовых типов, таких как double, float, int, string и т. Д. -проверка, делая большие успехи, мысль пришла мне в голову. Есть несколько способов доступа к методу расширения. Давайте создадим контейнерный класс с именем Extensions и добавим базовый метод расширения (сначала), а также фиктивный класс, который мы назовем Dummy с помощью простого метода, который использует наш метод расширения с именем DoIt.

public static class Extensions {
    public static double ToRadians(this double degrees) => degrees * Math.PI / 180.0;
}
public class Dummy {
    public void DoIt() {
        double radians = Extensions.ToRadians(45.0);
        double degrees = 90.0;
        radians = degrees.ToRadians();
    }
}

Не самый элегантный пример, но он демонстрирует широко известный доступ к методам расширения. Теперь давайте создадим идиотское и бессмысленное расширение под названием WasteOfTime для нашего класса Dummy, но внутри класса Extensions.

Я не уверен, почему вы это сделаете, но ради вопроса, давайте сделаем это!

public static class Extensions {
    ...
    public static void WasteOfTime(this Dummy dummy) { }
    ...
}

Хорошо, теперь у нас есть этот прекрасный маленький метод, который должен был быть помещен в класс Dummy. Итак, поскольку методы расширения работают с экземплярами типов, вы должны иметь возможность вызывать WasteOfTime из специального метода Dummy class ', называемого DoIt.

public void DoIt() {
    ...
    WasteOfTime();
    ...
}

О, но подождите, вы не можете этого сделать! Метод не может быть найден! Давайте уточним это по ключевому слову this!

this.WasteOfTime();

Это лучше, он компилируется! Оно работает! Это пустая трата времени! Круто!


Важное примечание

Я бы НЕ подумал бы сделать это на самом деле, но из любопытства я попробовал. Если вы можете привести веский пример того, почему это может быть хорошей идеей, не стесняйтесь поделиться, но я считаю, что это один из них; о чем вы думали типы реализаций.


Вопрос

Почему я должен был квалифицировать метод расширения, поскольку современные компиляторы устраняют необходимость в квалификационных полях, свойствах и методах с ключевым словом this?

Единственное, о чем я могу думать, это то, что метод расширения технически статичен по отношению к базовому классу.

1 Ответ

0 голосов
/ 24 января 2019

Во-первых, я отмечу, что есть вполне веские причины для вызова методов расширения на this. Например, вы, возможно, пишете класс коллекции и хотите использовать в нем LINQ. В этом нет ничего плохого. Теперь с точки зрения вопроса:

Почему я должен был квалифицировать метод расширения, поскольку современные компиляторы устраняют необходимость в полях, свойствах и методах с помощью ключевого слова this?

Дело не в современности компилятора, а в том, что говорится в спецификации языка. От ECMA-334 , раздел 12.7.6.3:

В вызове метода (§12.6.6.2) одной из форм

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )

если при обычной обработке вызова не найдено применимых методов, делается попытка обработать конструкцию как вызов метода расширения. Если expr или любое из аргументов имеет тип времени компиляции dynamic, методы расширения не будут применяться.

Вызов метода в форме Method() равен , а не в одной из этих форм, так как expr.

Так что компилятор просто подчиняется правилам спецификации. Что касается того, почему он разработан таким образом, это немного отличается. Я не знаю деталей этого (хотя я могу видеть, находятся ли они в одной из аннотированных версий спецификации), но я подозреваю, что факт, что Foo() может ссылаться на метод экземпляра или статический метод в текущий класс или любой из базовых классов делает все это немного сложнее. (Начиная с C # 6, это также может быть статический метод в любом из методов, импортируемых директивой using static, обратите внимание ...)

...