Я фанат методов расширения в C #, но не смог успешно добавить метод расширения в статический класс, такой как Console.
Например, если я хочу добавить в консоль расширение, называемое «WriteBlueLine», чтобы я мог перейти:
Console.WriteBlueLine("This text is blue");
Я попробовал это, добавив локальный, публичный статический метод, с консолью в качестве параметра 'this' ... но без кубиков!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
Это не добавило метод 'WriteBlueLine' в консоль ... я делаю это неправильно? Или просить невозможного?
c#
static
extension-methods
Леон Бамбрик
источник
источник
Helpers.WriteBlueLine(null, "Hi");
:)Ответы:
Методы расширения требуют переменную экземпляра (значение) для объекта. Вы можете, однако, написать статическую оболочку вокруг
ConfigurationManager
интерфейса. Если вы реализуете оболочку, вам не нужен метод расширения, поскольку вы можете просто добавить метод напрямую.источник
Можете ли вы добавить статические расширения для классов в C #? Нет, но вы можете сделать это:
Вот как это работает. Хотя технически вы не можете написать статические методы расширения, вместо этого этот код использует лазейку в методах расширения. Эта лазейка заключается в том, что вы можете вызывать методы расширения для нулевых объектов, не получая нулевое исключение (если вы не обращаетесь к чему-либо через @this).
Итак, вот как вы могли бы использовать это:
Теперь, ПОЧЕМУ я выбрал вызов конструктора по умолчанию в качестве примера, и почему я просто не могу вернуть new T () в первом фрагменте кода, не выполняя весь этот мусор Expression? Ну, сегодня ваш счастливый день, потому что вы получаете 2fer. Как знает любой продвинутый разработчик .NET, new T () работает медленно, поскольку генерирует вызов System.Activator, который использует отражение, чтобы получить конструктор по умолчанию перед вызовом. Черт бы тебя побрал, Microsoft! Однако мой код вызывает конструктор объекта по умолчанию напрямую.
Статические расширения были бы лучше, чем это, но отчаянные времена требуют отчаянных мер.
источник
XConsole
,ConsoleHelper
и так далее.(null as DataSet).Create();
может бытьdefault(DataSet).Create();
.Это невозможно.
И да, я думаю, что MS допустил ошибку здесь.
Их решение не имеет смысла и вынуждает программистов писать (как описано выше) бессмысленный класс-обертку.
Вот хороший пример: Попытка расширить статический класс модульного тестирования MS Assert: я хочу еще 1 метод Assert
AreEqual(x1,x2)
.Единственный способ сделать это - указать на разные классы или написать обертку вокруг сотен различных методов Assert. Почему!?
Если было принято решение разрешить расширения экземпляров, я не вижу логической причины не разрешать статические расширения. Аргументы о секционировании библиотек не вступают в силу после того, как экземпляры могут быть расширены.
источник
Assert.Throws
ответить на этот вопрос stackoverflow.com/questions/113395/…Я наткнулся на эту тему, пытаясь найти ответ на тот же вопрос, который имел ОП. Я не нашел ответ, который хотел, но в итоге я сделал это.
И я использую это так:
источник
Может быть, вы могли бы добавить статический класс с вашим собственным пространством имен и тем же именем класса:
источник
Начиная с C # 7 это не поддерживается. Тем не менее, есть дискуссии об интеграции чего-то подобного в C # 8 и предложения, которые стоит поддержать .
источник
Нет. Для определения метода расширения требуется экземпляр типа, который вы расширяете. Это неудачно; Я не уверен, почему это требуется ...
источник
Что касается методов расширения, сами методы расширения являются статическими; но они вызываются так, как если бы они были методами экземпляра. Поскольку статический класс не является экземпляром, у вас никогда не будет экземпляра класса, из которого будет вызываться метод расширения. По этой причине компилятор не позволяет определять методы расширения для статических классов.
Г-н Obnoxious пишет: «Как знает любой продвинутый разработчик .NET, новый T () работает медленно, потому что он генерирует вызов System.Activator, который использует отражение, чтобы получить конструктор по умолчанию перед его вызовом».
New () компилируется в инструкцию IL "newobj", если тип известен во время компиляции. Newobj принимает конструктор для прямого вызова. Вызовы System.Activator.CreateInstance () компилируются в инструкцию IL "call" для вызова System.Activator.CreateInstance (). New () при использовании против универсальных типов приведет к вызову System.Activator.CreateInstance (). Пост г-на Ненавистника был неясен в этом вопросе ... и, ну, в общем, неприятен.
Этот код:
производит этот IL:
источник
Вы не можете добавить статические методы к типу. Вы можете добавлять (псевдо) методы экземпляра только к экземпляру типа.
Точка
this
модификатора, чтобы сказать С # компилятора передать экземпляр на левой стороне в.
качестве первого параметра метода статического / расширения.В случае добавления статических методов к типу нет экземпляра для передачи первого параметра.
источник
Я пытался сделать это с System.Environment, когда я изучал методы расширения и не увенчался успехом. Причина в том, как другие упоминают, потому что методы расширения требуют экземпляра класса.
источник
Невозможно написать метод расширения, однако можно имитировать запрашиваемое вами поведение.
Это позволит вам вызывать Console.WriteBlueLine (fooText) в других классах. Если другие классы хотят получить доступ к другим статическим функциям Консоли, на них нужно будет явно ссылаться через их пространство имен.
Вы всегда можете добавить все методы в класс замены, если хотите, чтобы все они были в одном месте.
Так что у вас было бы что-то вроде
Это обеспечит то поведение, которое вы ищете.
* Примечание. Консоль должна быть добавлена через пространство имен, в которое вы ее поместили.
источник
да, в ограниченном смысле.
Это работает, но Консоль не, потому что это статично.
Это работает, потому что пока оно не в том же пространстве имен. Проблема в том, что вы должны написать статический метод прокси для каждого метода, который есть в System.Console. Это не обязательно плохо, так как вы можете добавить что-то вроде этого:
или
Это работает так, что вы подключаете что-то к стандартному WriteLine. Это может быть счетчик строк или фильтр плохих слов или что-то еще. Всякий раз, когда вы просто указываете Консоль в своем пространстве имен, скажем, WebProject1 и импортируете пространство имен System, WebProject1.Console будет выбираться вместо System.Console по умолчанию для этих классов в пространстве имен WebProject1. Таким образом, этот код превратит все вызовы Console.WriteLine в синий, поскольку вы никогда не указывали System.Console.WriteLine.
источник
Следующее было отклонено в качестве редактирования ответа tvanfosson. Меня попросили внести это как мой собственный ответ. Я воспользовался его предложением и закончил реализацию
ConfigurationManager
обертки. В принципе, я просто заполнил...
ответ в Тванфоссоне.источник
Вы можете использовать приведение к null, чтобы заставить его работать.
Расширение:
Ваш тип:
источник
Вы МОЖЕТЕ сделать это, если вы хотите немного «заморозить» его, создав переменную статического класса и присвоив ей значение null. Однако этот метод не будет доступен для статических вызовов класса, поэтому не уверен, насколько он будет полезен:
источник