Почему не поддерживаются методы расширения класса С#?

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

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

Метод фактически не входит в класс. Вот почему вы не можете получить доступ к закрытым членам из метода расширения. Методы расширения изменяют только синтаксис С# и не нарушают концепцию доступности OOP. Фактически, если вы пишете метод расширения и обычный статический метод, который делает то же самое, тогда декомпилируйте 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 способом. Очевидно, команда С# почувствовала, что читаемость, полученная LINQ, стоит того, но она задает вопрос: "Почему они остановились там?"

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

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

Команда действительно рассмотрела возможность реализации свойств расширения на С# 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

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

public static T DoSomething<T>(this T @class) 
    where T:Type
{
    // access static methods via reflection...
    return @class;
}

Ответ 4

Я считаю, что ответ на ваш вопрос 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 методы для статических классов.

Ответ 5

Статические расширения возможны в 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

Ответ 6

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

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