Почему не поддерживаются методы расширения статического класса C #? - PullRequest
56 голосов
/ 05 февраля 2011

Я знаю из этого вопроса , что методы расширения могут работать только с экземплярами класса, но не над самим статическим классом.Это означает, что я не могу расширять полезные статические классы, такие как Convert и Math.

. Что я хочу знать, так это почему?По ссылке выше есть несколько предложений о том, как команда C # могла бы реализовать такую ​​функциональность.Есть ли какая-то философская причина, почему она не поддерживается?

Например, вот обоснование , почему нет встроенного расширения LINQ ForEach<T> для IEnumerable<T>.

Ответы [ 6 ]

72 голосов
/ 06 февраля 2011

команда C # могла бы реализовать такую ​​функциональность.Есть ли философская причина, почему она не поддерживается?

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

В частности, предлагаемая функцияничего не делает для LINQ;методы расширения были добавлены, чтобы заставить LINQ работать.Все, что не помогло LINQ, было очень трудно получить в C # 3.0;у нас было много работы по расписанию и не так много времени, чтобы сделать это. (Я был удивлен, что автоматические свойства сделали это.) Сокращение ненужной функции перед тем, как даже разработать ее, сэкономило много времени и усилий, которые были потрачены на другиевещи, которые делают , заставляют LINQ работать.

Короче говоря: предлагаемая функция никогда не встречала планку чистой выгоды по сравнению с затратами, и у нас всегда были более важные функции, чтобы тратить наше ограниченное времяи усилия на.

12 голосов
/ 06 февраля 2011

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

Как работают методы расширения

Во-первых, важно понимать, что расширения - это просто синтаксический сахар для статических методов.

// Say you have an extension method that looks like this:
class Extensions
{
    public static void Extend(this SomeClass foo) {}
}

// Here's how you call it
SomeClass myClass;
myClass.Extend();

// The compiler converts it to this:
Extensions.Extend(myClass);

Метод фактически не становится частью класса.Вот почему вы не можете получить доступ к закрытым членам из метода расширения.Методы расширения изменяют только синтаксис C # и не нарушают концепцию доступности ООП.Фактически, если вы пишете метод расширения и обычный статический метод, которые делают одно и то же, а затем декомпилируете MSIL, они точно такие же .

Почему существуют методы расширения

Так что, если они не добавляют реальной функциональности, зачем вообще использовать методы расширения?Ответ - LINQ:

// LINQ makes this easy to read
array.Where(i => i&1 == 0).Select(i => i*i);

// Without extension methods, we would have to do it like this
Enumerable.Select(Enumerable.Where(array, i => i&1 == 0), i => i*i);

В некотором смысле, все LINQ - просто синтаксический сахар, поскольку все, что он может сделать, может быть написано неуклюжим, не LINQy способом.Очевидно, что команда C # чувствовала, что читаемость, достигнутая LINQ, стоила того, но напрашивается вопрос: «Почему они остановились на этом?»

Почему не другие типы расширений?

Эрик Липперт,один из разработчиков компилятора C #, описанный в сообщении в блоге о том, что огромная часть C # 3 создавала все конструкции, необходимые для LINQ: "неявно типизированных локальных элементов, анонимных типов, лямбда-выражений, расширенийметоды, инициализаторы объектов и коллекций, понимание запросов, деревья выражений и [и] улучшенный вывод типов методов. " Поскольку команда C # была самой ограниченной группой ресурсов для выпуска 2008 .NET, дополнительные типы расширений, которые не былиt строго необходимые для LINQ не были включены.

Команда решила реализовать свойства расширения в C # 4 и фактически написала рабочий прототип, но он был отброшен, когда обнаружил, что команда WPF не будет реализована как реализованная (который был одним из мотиваторов для функции).Позже Эрик Липпер сказал, что они рассмотрели методы расширения для статических классов, но не смогли оправдать реальные выгоды от затрат на внедрение, тестирование и обслуживание.

Обходное решение

Можно написать метод расширения, который приближается:

public static TResult DoSomething<TType, TResult>(this TType @class)
    {
        // access static methods with System.Reflection
        return default(TResult);
    }

// This works, but poorly
typeof(Math).DoSomething();
typeof(Convert).DoSomething();

Но это довольно уродливо.Он требует рефлексии и не может поддерживать интеллектуальную типизацию, поскольку любой Type может вызывать его, и это, скорее всего, не та функциональность, для которой он предназначен.

3 голосов
/ 05 февраля 2011

Я полагаю, что ответ на ваш вопрос because it doesn't make any sense to extend with static methods. Основная причина введения Extension methods - это не класс extending, которым вы не владеете. Основная причина в том, что это позволит сократить вложенность методов в примерах, подобных этим:

 Enumerable.Select(Enumerable.Where(arr, i => i & 1 == 0), i => i*i); // not the best thing I ever read

 arr.Where(i => i&1 == 0).Select(i => i*i); // wow, I see! These are squares for odd numbers

Вот почему нет такой точки, чтобы иметь extension методы для статических классов.

3 голосов
/ 05 февраля 2011

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

public static T DoSomething<T>(this T @class) 
    where T:Type
{
    // access static methods via reflection...
    return @class;
}
2 голосов
/ 02 марта 2015

Статические расширения возможны в F #:

type Platform = 
    | Win32
    | X64
    override this.ToString() = 
        match FSharpValue.GetUnionFields(this, typeof<Platform>) with
        | case, _ -> case.Name.Replace('X', 'x')

type Environment with
    static member Platform =
        if System.IntPtr.Size = 8 then Platform.X64 else Platform.Win32
1 голос
/ 05 февраля 2011

Ну, это не только не реализовано, но и приведет к путанице, где метод принадлежит? Статические расширения были введены потому, что linq появился в более поздней версии, и для поддержки linq простым способом кода статические расширения полезны.

Статические расширения полезны только для того, чтобы сделать код более читабельным. Это не имеет значения во время выполнения или компиляции.

...