Скрытые возможности C #? [закрыто]

Это пришло мне в голову после того, как я узнал следующее из этого вопроса :

where T : struct

Мы, разработчики C #, все знаем основы C #. Я имею в виду объявления, условия, циклы, операторы и т. Д.

Некоторые из нас даже освоили такие вещи, как Generics , анонимные типы , лямбды , LINQ , ...

Но каковы наиболее скрытые возможности или уловки C #, которые даже фанаты C #, наркоманы, эксперты едва знают?

Вот некоторые выявленные особенности:


Ключевые слова

Атрибуты

Синтаксис

Особенности языка

Особенности Visual Studio

Фреймворк

Методы и свойства

Советы и хитрости

  • Хороший метод для обработчиков событий от Andreas HR Nilsson
  • Прописные сравнения Джона
  • Доступ к анонимным типам без отражения от dp
  • Быстрый способ лениво создавать свойства коллекции с помощью Will
  • JavaScript-подобные анонимные inline-функции от roosteronacid

Другой

12.08.2008 16:32:24
30 ОТВЕТОВ

« доходность » пришла бы мне в голову. Некоторые из атрибутов, таких как [DefaultValue ()] , также среди моих любимых.

Ключевое слово « var » немного более известно, но то, что вы можете использовать его и в приложениях .NET 2.0 (если вы используете компилятор .NET 3.5 и устанавливаете его для вывода кода 2.0), кажется не очень известным хорошо.

Редактировать: kokos, спасибо за указание ?? оператор, это действительно очень полезно. Так как в нем сложно найти Google (так как ?? просто игнорируется), вот страница документации MSDN для этого оператора: ?? Оператор (C # Reference)

209
23.05.2011 11:18:11
В документации по умолчанию указано, что на самом деле значение свойства не установлено. Это всего лишь помощник для визуализаторов и генераторов кода.
Boris Callens 8.11.2008 01:18:27
Что касается DefaultValue: тем временем некоторые библиотеки используют его. ASP.net MVC использует DefaultValue для параметров действия контроллера (что очень полезно для необнуляемых типов). Строго говоря, конечно, это генератор кода, так как значение устанавливается не компилятором, а кодом MVC.
Michael Stum♦ 10.01.2010 01:32:53
Название для оператор - оператор "Null Coalescing"
Armstrongest 29.03.2010 18:23:41
yield - мой любимый, хотя оператор коалесценции там. Я не вижу ничего о CAS или подписи сборок, строгих именах, GAC ... Полагаю, CAS - это только C # ... но многие разработчики не имеют ни малейшего представления о безопасности.
BrainSlugs83 28.02.2012 21:05:27
  1. ?? - оператор коалесцирования
  2. using ( оператор / директива ) - отличное ключевое слово, которое можно использовать не только для вызова Dispose
  3. только для чтения - следует использовать больше
  4. сетевые модули - очень плохо, нет поддержки в Visual Studio
104
30.04.2010 10:31:14
using может также использоваться для псевдонима длинного пространства имен для более удобной строки, то есть: using ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; Здесь есть еще: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R. 9.12.2008 15:41:55
Это действительно не то же самое. При вызове Dispose вы можете использовать оператор using, когда для псевдонимов типов вы используете директиву using.
Øyvind Skaar 11.01.2009 19:29:48
На всякий случай, если вы хотите, чтобы имя # 1 (как вы сделали с троичным оператором), ?? называется нулевым оператором слияния.
J. Steen 23.04.2009 12:47:19
@LucasAardvark: как упомянул Дж. Стин, он называется оператором нулевого слияния. Ищите это!
kokos 21.06.2009 01:54:10
Искать ?? оператор в Google try: google.com/search?q=c%23+%3F%3F+operator
backslash17 25.12.2009 22:06:33

Два моих личных фаворита, которые я вижу редко используемые:

  1. Фрагменты (особенно для свойств, которые были сделаны еще лучше для Visual Studio 2008)
  2. ObsoleteAttribute
28
23.05.2011 11:19:28
Мне очень нравится фрагмент переключателя. Упрощает включение enum sooo;)
OregonGhost 30.03.2009 12:34:27
я регулярно использую фрагмент для свойств, вызывающих OnPropertyChanged в сеттере. очень кстати.
Botz3000 19.05.2009 22:32:39
Являются ли фрагменты кода функцией Visual Studio? Вместо C # / компилятор?
maxwellb 13.06.2009 22:40:57
фрагменты являются частью визуального ярлыка студии ctrl - k + ctrl x
Maslow 14.08.2009 19:23:00
еще лучше, например: написать «for» или «switch», а затем дважды нажать клавишу «tab»
murki 15.10.2009 22:24:24

Честно говоря, специалисты по определению должны знать этот материал. Но чтобы ответить на ваш вопрос: таблица встроенных типов (C # Reference)

Компилятор, помечающий числа, широко известен следующими способами:

Decimal = M
Float = F
Double = D

// for example
double d = 30D;

Однако они более неясны:

Long = L
Unsigned Long = UL
Unsigned Int = U
75
23.05.2011 11:26:38
Каждый раз, когда я имею дело с десятичными числами, я должен посмотреть на m. Это только я или я не очень интуитивен? :)
OregonGhost 30.03.2009 10:56:24
Синтаксис M происходит от старого типа VB, который называется Money. М == Деньги == Десятичные.
Nick Berardi 30.03.2009 19:46:11
Нет, все, кроме Int32, автоматически выводится компилятором на основе типа слева от него
Nick Berardi 28.06.2009 10:59:13
@Nick: приятно - мне нравится изучать историю, стоящую за кодом.
IAbstract 28.01.2010 06:24:07
Я помню M = Decimal / D = Double точно так же, как я помню port / starboard: правый борт означает «Право» и имеет больше «R». У десятичного есть М, а у двойного нет.
goldenratio 1.09.2011 22:07:40

Я давно не знал ключевое слово "как".

MyClass myObject = (MyClass) obj;

против

MyClass myObject = obj as MyClass;

Второй вернет ноль, если obj не является MyClass, а не сгенерирует исключение приведения класса.

286
12.08.2008 16:42:04
Не переусердствуйте, хотя. Многие люди, кажется, используют это потому, что предпочитают синтаксис, хотя им нужна семантика (ToType) x.
Scott Langham 19.09.2008 18:07:42
Я не верю, что он предлагает лучшую производительность. Вы профилировали это? (Очевидно, что это происходит при сбое приведения ... но когда вы используете приведение (MyClass), сбои являются исключительными ... и крайне редкими (если они вообще случаются), поэтому это не имеет значения.
Scott Langham 21.01.2009 13:01:31
Это только более эффективно, если в обычном случае происходит сбой приведения. В противном случае объект прямого приведения (типа) работает быстрее. Для прямого броска требуется больше времени, чтобы вызвать исключение, чем для возврата нулевого значения.
Spence 26.01.2009 14:54:52
Прямо по тем же строкам ключевого слова «как» ... ключевое слово «есть» так же полезно.
dkpatt 7.05.2009 19:09:29
Вы можете использовать его и получить исключение NullReferenceException в будущем, если раньше у вас могло быть InvalidCastException.
Andrei Rînea 2.09.2009 07:55:23
  • TransactionScope и DependentTransaction в System.Transactions - это простой способ использовать обработку транзакций в .NET - это не только для транзакций базы данных.
  • String.IsNullOrEmpty - это то, что я удивлен, узнав, что многие разработчики не знают о
  • List.ForEach - перебирать ваш общий список, используя метод делегата

Есть и другие, но это три очевидных из верхней части моей головы ...

68
27.09.2009 19:31:34
Я обнаружил, что TransactionScope активно продвигает транзакции в распределенный режим, который использует DTC. Когда будет задействован DTC, вам, вероятно, придется иметь дело с безопасностью DCOM. Я склонен избегать боли, используя нативные транзакции.
Hans Malherbe 12.07.2009 18:27:24
Этот List.ForEach работает быстрее, чем foreach, или for (;;) полностью помешан на этом. ForEach использует делегат метода / функции для реализации поведения. Это, прежде всего, означает худшую локальность кэша, потому что код обычно выполняется дальше (в памяти) от фактического цикла. Во-вторых, все, что вам действительно нужно сделать, чтобы убедиться, что это медленнее, это посмотреть сгенерированный нативный код. В List.ForEach происходит намного больше вещей, чем вы думаете.
John Leidegren 5.08.2009 17:13:12
Абсолютно помешанные? Ну, я обнаружил .ForEach быть быстрее, чем все другие варианты. Смотрите jerrytech.blogspot.com/2010/02/… если вы сомневаетесь во мне. Всегда сомневайся;) Код там - запусти его сам и посмотри.
Jerry Nixon 8.09.2010 22:28:59
С другой стороны, Патрик Смаккья говорит обратное: ForEach медленнее, чем For. codebetter.com/blogs/patricksmacchia/archive/2008/11/19/…
James 19.09.2010 20:04:03
Теперь есть также String.IsNullOrWhitespace
Ray 3.02.2011 11:53:14

Атрибуты в целом, но больше всего DebuggerDisplay . Спасает тебя годы.

226
26.04.2009 16:34:20
Использование атрибута DebuggerDisplay (MSDN): msdn.microsoft.com/en-us/library/x810d419.aspx
Jon Adams 26.09.2008 17:14:03

Я склонен находить, что большинство разработчиков на C # не знают о «обнуляемых» типах. В основном, примитивы, которые могут иметь нулевое значение.

double? num1 = null; 
double num2 = num1 ?? -100;

Установите обнуляемую двойные, num1 , в нуль, а затем установить регулярную двойные, num2 , чтобы num1 или -100 , если num1 был нулевой.

http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx

Еще одна вещь о типе Nullable:

DateTime? tmp = new DateTime();
tmp = null;
return tmp.ToString();

это возврат String.Empty. Проверьте эту ссылку для более подробной информации

198
23.05.2017 10:31:39
DateTime не может быть установлен в ноль.
Jason Jackson 30.09.2008 01:03:50
Так что же, "int" - это синтаксический сахар C # для System.Int32? На самом деле существует поддержка компилятора, основанная на типах Nullable, позволяющая, например, установить для них значение null (что невозможно сделать с помощью только общих структур) и поместить их в качестве основного типа.
P Daddy 17.11.2008 07:00:16
@P Папа - да, int - это синтаксический сахар для System.Int32. Они полностью взаимозаменяемы, как и int? === Int32? === Nullable <Int32> === Nullable <int>
cjk 8.01.2009 18:22:28
@ck: Да, int - это псевдоним System.Int32, как T? это псевдоним для Nullable <T>, но это не просто синтаксический сахар. Это определенная часть языка. Псевдонимы не только облегчают чтение кода, но и лучше соответствуют нашей модели. Выражаете Nullable <Double> как двойной? подчеркивает перспективу, что содержащееся таким образом значение является (или может быть) двойным, а не просто какой-то общей структурой, созданной для типа Double. (продолжение)
P Daddy 15.06.2009 04:09:19
... В любом случае, аргумент был не о псевдонимах (это была просто плохая аналогия, я полагаю), но что обнуляемые типы - используя любой синтаксис, который вы предпочитаете - действительно являются языковой функцией, а не просто продуктом дженериков. Вы не можете воспроизвести все функциональные возможности значений NULL (сравнение с / присваивание NULL, переадресация операторов, бокс базового типа или NULL, совместимость с NULL-объединением и asоператорами) только с помощью обобщений. Одно только Nullable <T> является рудиментарным и далеко не звездным, но концепция обнуляемых типов как части языка - это задница.
P Daddy 15.06.2009 04:15:08

Мне часто приходилось сталкиваться с необходимостью сохранения общего параметра-объекта в viewstate в базовом классе.

public abstract class BaseListControl<ListType,KeyType,ParameterType>
                 : UserControl 
                 where ListType : BaseListType
                 && ParameterType : BaseParameterType, new
{

    private const string viewStateFilterKey = "FilterKey";

    protected ParameterType Filters
    {
        get
        {
            if (ViewState[viewStateFilterKey] == null)
                ViewState[viewStateFilterKey]= new ParameterType();

            return ViewState[viewStateFilterKey] as ParameterType;
        }
        set
        {
            ViewState[viewStateFilterKey] = value;
        }
    }

}

Использование:

private void SomeEventHappened(object sender, EventArgs e)
{
    Filters.SomeValue = SomeControl.SelectedValue;
}

private void TimeToFetchSomeData()
{
    GridView.DataSource = Repository.GetList(Filters);
}

Этот маленький трюк с «где ParameterType: BaseParameterType, new» - это то, что заставляет его действительно работать.

С помощью этого свойства в моем базовом классе я могу автоматизировать обработку подкачки страниц, установить значения фильтров для фильтрации вида сетки, упростить сортировку и т. Д.

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

15
23.05.2011 11:28:48
Может быть, я ненормальный, но я не уверен, что понимаю код. Не могли бы вы опубликовать более полный пример?
ilivewithian 23.04.2009 11:18:02
Это довольно просто на самом деле. Если у вас есть GridView с парой DropDownLists для фильтрации содержимого, вы просто помещаете значения в объект фильтра, который сохраняется между обратными передачами, и отправляете его в качестве параметра в метод, который выбирает данные из БД. Вы просто реализуете свой UserControl, наследующий от BaseListControl, а база заботится о сохранении «состояния» между обратными передачами.
Lars Mæhlum 23.04.2009 14:22:51
что значит "маленькая хитрость"? Вы имеете в виду тот факт, что вы не можете создать параметризованный тип внутри универсального, если общие ограничения не содержат предложение "new"?
Andy Dent 3.10.2009 23:19:52
Нет, маленькая хитрость ограничивает BaseParameterType. Немного опечатка: \
Lars Mæhlum 7.10.2009 07:57:30

@ Эд, я немного неохотно публикую это, так как это немного больше, чем придирки. Однако я хотел бы отметить, что в вашем примере кода:

MyClass c;
  if (obj is MyClass)
    c = obj as MyClass

Если вы собираетесь использовать «is», зачем использовать безопасное приведение с использованием «as»? Если вы убедились, что obj - это действительно MyClass, стандартное приведение:

c = (MyClass)obj

... никогда не потерпит неудачу.

Точно так же вы могли бы просто сказать:

MyClass c = obj as MyClass;
if(c != null)
{
   ...
}

Я не знаю достаточно о внутренностях .NET, чтобы быть уверенным, но мои инстинкты говорят мне, что это сократит не более двух операций приведения типов до максимум одной. Вряд ли в любом случае сломать процессинговый банк; лично я думаю, что последняя форма выглядит чище.

103
12.08.2008 18:03:12
Если приведение относится к точному типу (приведение к «A», когда объект является «A», а не из него), прямое приведение происходит в ~ 3 раза быстрее, чем «as». При приведении к производному типу (приведение к «A», когда объект «B», что происходит от «A»), прямое приведение на ~ 0.1x медленнее, чем «as». «есть», то «как» просто глупо.
P Daddy 17.11.2008 07:15:44
Нет, но вы можете написать "if ((c = obj as MyClass)! = Null)".
Dave Van den Eynde 25.03.2009 12:14:11
isи asне будет делать приведения пользователя. Таким образом, приведенный выше код спрашивает у isоператора, является ли объект obj производным от MyClass (или имеет неявное приведение системы, определенное). Кроме того, isне удается null. Оба этих крайних случая могут быть важны для вашего кода. Например, вы можете написать: « if( obj == null || obj is MyClass ) c = (MyClass)obj; Но это строго отличается от: try { c = (MyClass)obj; } catch { }так как первый не будет выполнять какие-либо определенные пользователем преобразования, но последний будет выполнять. Без nullпроверки первый также не будет установлен, cкогда objесть null.
Adam Luter 9.09.2009 12:02:43
В IL приведение идет к CASTCLASS, но as / is идет к инструкции ISINST.
John Gibb 18.04.2011 17:39:07
Я выполнил тест для этого, произвел приведение IEnumerable<int>к List<int>и приведение к object( new object()) IEnumerable<int>, чтобы убедиться в отсутствии ошибок: прямое приведение: 5,43 нс, is-> как приведение: 6,75 нс, приведение: 5,69 нс. Затем тестирование неверных приведений: прямое приведение: 3125000 нс, приведение: 5,41 нс. Вывод: перестаньте беспокоиться о факторе 1%, и просто убедитесь, что вы используете /, поскольку приведение может быть недопустимым, потому что исключения (также если они обрабатываются) ОЧЕНЬ медленны по сравнению с приведением, мы говорим о факторе 578000 медленнее. Помните, что последняя часть, остальное не имеет значения (.Net FW 4.0, выпуск сборки)
Aidiakapi 13.09.2011 11:06:34

Все остальное, плюс

1) неявные дженерики (почему только на методах, а не на классах?)

void GenericMethod<T>( T input ) { ... }

//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23);      //Is enough.

2) простые лямбды с одним параметром:

x => x.ToString() //simplify so many calls

3) анонимные типы и инициализаторы:

//Duck-typed: works with any .Add method.
var colours = new Dictionary<string, string> {
    { "red", "#ff0000" },
    { "green", "#00ff00" },
    { "blue", "#0000ff" }
};

int[] arrayOfInt = { 1, 2, 3, 4, 5 };

Другой:

4) Авто свойства могут иметь разные области видимости:

public int MyId { get; private set; }

Спасибо @pzycoman за напоминание:

5) Псевдонимы пространства имен (не то, что вам, вероятно, понадобится это конкретное различие):

using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();
305
13.02.2012 21:56:02
в # 3 вы можете сделать Enumerable.Range (1,5)
Echostorm 7.10.2008 14:08:57
я думаю, что вы смогли инициализировать массивы с помощью int [] nums = {1,2,3}; с версии 1.0 :) даже не нужно ключевое слово "new"
Lucas 7.10.2008 23:26:48
также лямбда без параметров () => DoSomething ();
Pablo Retyk 12.01.2009 08:38:12
Я использовал оба {получить; внутренний набор; } и получить; защищенный набор; }, так что этот шаблон является последовательным.
Keith 4.05.2009 21:23:16
@Kirk Broadhurst - вы правы - new web.Control()также будет работать в этом примере. В ::синтаксических заставляет его лечить префикс как псевдоним пространства имен, так что вы могли бы иметь класс с именем webи web::Controlсинтаксис будет по- прежнему работать, в то время как web.Controlсинтаксис не будет знать , проверять ли класс или пространство имен. Из-за этого я обычно использую ::псевдонимы пространства имен.
Keith 8.03.2010 11:32:08

Вот полезный пример для регулярных выражений и путей к файлам:

"c:\\program files\\oldway"
@"c:\program file\newway"

Символ @ указывает компилятору игнорировать любые escape-символы в строке.

146
12.08.2008 19:01:09
Кроме того, константа @ принимает новые строки внутри. Идеально подходит при назначении многострочного сценария в строку.
Tor Haugen 19.11.2008 16:17:06
Не забудьте также избежать кавычек, просто удвойте их, другими словами. [code] var candy = @ "Мне нравятся" "красные" "леденцы."; [/ code]
Dave 10.01.2009 14:39:21
Я склонен строить пути с помощью Path.Combine. Я определенно использую @ для регулярных выражений!
Dan McClain 16.06.2009 12:45:08
@new также является переменной вместо ключевого слова: @this, @int, @return, @interface ... и так далее :)
IAbstract 28.01.2010 05:59:24
Это никуда не денется: но каковы наиболее скрытые функции или уловки C #, которые даже фанаты C #, наркоманы, эксперты едва знают?
publicgk 16.08.2011 11:15:49

@Brad Barker

Я думаю, что если вам нужно использовать обнуляемые типы, лучше использовать Nullable <.T>, а не знак вопроса. Это делает очевидным, что происходит волшебство. Не уверен, почему кто-то захочет использовать Nullable <.bool>. :-)

Кшиштоф Квалина (один из авторов Руководства по разработке фреймворка) имеет хороший пост здесь: http://blogs.msdn.com/kcwalina/archive/2008/07/16/Nullable.aspx

И у Майка Хэдлоу есть хороший пост на Nullability Voodoo

6
12.08.2008 18:44:54
Не уверен, что согласен с Майком Хэдлоу. Похоже, кто-то, кто провел долгое время, используя языки и базы данных без хорошей нулевой поддержки, и немного «боится» изменений. Использование нуля в деловых терминах обычно очевидно. Это означает «не знаю» или «не имеет ни одного» (то есть «не имеет конечной даты»).
cbp 29.11.2008 05:46:25
«Не уверен, почему кто-то захочет использовать Nullable <.bool>, хотя». Как насчет того, когда вы взаимодействуете со столбцами BIT из базы данных SQL Server? Тип данных BIT в T-SQL может возвращать 1, 0 или NULL и может быть непосредственно преобразован в Nullable <Bool> с помощью .NET Nullables чрезвычайно полезны при работе с данными в базах данных, поскольку «типы значений» могут фактически быть NULL.
Dan Diplo 21.07.2009 21:39:42
@cbp и @Dan Dilpo - Вы можете утверждать, что если вы допускаете пустые значения в типе значения, таком как bool, вам следует использовать что-то еще.
Iain Holder 22.07.2009 19:59:54
Легко, пустой бул это FileNotFound !! thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
Axeman 2.05.2011 12:34:36

Вот некоторые интересные скрытые возможности C # в форме недокументированных ключевых слов C #:

__makeref

__reftype

__refvalue

__arglist

Это недокументированные ключевые слова C # (даже Visual Studio распознает их!), Которые были добавлены для более эффективной упаковки / распаковки до использования обобщений. Они работают в координации со структурой System.TypedReference.

Также есть __arglist, который используется для списков параметров переменной длины.

Одна вещь, о которой мало кто знает, это System.WeakReference - очень полезный класс, который отслеживает объект, но все же позволяет сборщику мусора собирать его.

Наиболее полезной «скрытой» функцией будет ключевое слово yield return. Это на самом деле не скрыто, но многие люди не знают об этом. LINQ построен на этом; это позволяет выполнять запросы с задержкой, генерируя конечный автомат. Раймонд Чен недавно опубликовал информацию о внутренних мелочах .

193
10.11.2011 17:14:12
Подробнее о недокументированных ключевых слов Питера Бромберга . Я до сих пор не понимаю, есть ли причины их использовать.
HuBeZa 31.01.2011 11:53:52
@HuBeZa с появлением дженериков, не так много (каких?) Веских причин использовать __refType, __makeref и __refvalue. Они были использованы в первую очередь, чтобы избежать бокса до дженериков в .NET 2.
Judah Gabriel Himango 31.01.2011 19:14:28
Мэтт, с введением обобщений в .NET 2, было мало оснований для использования этих ключевых слов, поскольку их целью было избежать бокса при работе с типами значений. См. Ссылку HuBeZa, а также см. Codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango 10.11.2011 17:13:23

Не уверен, почему кто-то захочет использовать Nullable <bool>. :-)

Верно, Неверно , FileNotFound ?

130
22.11.2008 07:39:07
если ожидается, что пользователь ответит на вопрос «да нет», тогда будет уместно использовать
Omar Kooheji 24.10.2008 12:38:56
Обнуляемые типы удобны для взаимодействия с базой данных, где столбцы таблицы часто обнуляются.
tuinstoel 1.01.2009 16:40:31
Да нет, может быть?
Dan Blair 22.05.2009 20:19:32
Сохраните значения ThreeState CheckBox
Shimmy 13.07.2009 15:04:47
Как в SQL: да / нет / неизвестно.
erikkallen 9.09.2009 11:30:07

В произвольном порядке:

Lists<>
Mutex

Ярлык новых определений свойств в Framework 3.5.

6
19.12.2009 10:49:32

Избегайте проверки на нулевые обработчики событий

Добавление пустого делегата к событиям при объявлении, устранение необходимости всегда проверять событие на null, прежде чем вызывать его, - это здорово. Пример:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

Позволь тебе сделать это

public void DoSomething()
{
    Click(this, "foo");
}

Вместо этого

public void DoSomething()
{
    // Unnecessary!
    MyClickHandler click = Click;
    if (click != null) // Unnecessary! 
    {
        click(this, "foo");
    }
}

Пожалуйста, также посмотрите эту связанную дискуссию и этот блог Эрика Липперта на эту тему (и возможные недостатки).

315
23.05.2017 11:55:01
Я полагаю, что проблема возникнет, если вы будете полагаться на эту технику, а затем вам придется сериализовать класс. Вы исключите событие, а затем при десериализации вы получите NullRefference ..... Так что можно просто придерживаться «старого способа» ведения дел. Это безопаснее.
sirrocco 13.10.2008 09:58:28
вы все равно можете установить свой обработчик событий на нуль, так что вы все равно можете получить нулевую ссылку, и у вас все еще есть условие гонки.
Robert Paulson 19.10.2008 23:00:14
Быстрый тест профиля показывает, что обработчик событий с фиктивной подпиской без нулевого теста занимает примерно в 2 раза больше времени, чем обработчик неподписанных событий с нулевым тестом. Обработчик многоадресных событий без нулевого теста занимает примерно в 3,5 раза больше времени, чем обработчик одноадресных событий с нулевым тестом.
P Daddy 17.11.2008 06:53:33
Это избавляет от необходимости нулевой проверки, просто всегда имея собственного подписчика. Даже как пустое событие, это несет накладные расходы, которые вы не хотите. Если нет подписчиков, вы вообще не хотите запускать событие, не всегда сначала запускайте пустое фиктивное событие. Я бы посчитал этот плохой код.
Keith 4.12.2008 14:49:53
Это ужасное предложение по причинам, приведенным в комментариях выше. Если вам нужно, чтобы ваш код выглядел «чистым», используйте метод расширения, чтобы проверить наличие нуля, затем вызовите событие. Кто-то с правами на изменение должен обязательно добавить минусы к этому ответу.
Greg 31.03.2009 04:29:01

Это не C # само по себе, но я не видел никого, кто действительно использует System.IO.Path.Combine()в той степени, в которой они должны. На самом деле, весь класс Path действительно полезен, но никто не использует его!

Готов поспорить, что каждое производственное приложение имеет следующий код, хотя и не должно:

string path = dir + "\\" + fileName;
752
13.08.2008 01:53:50

Символ @ указывает компилятору игнорировать любые escape-символы в строке.

Просто хотел уточнить это ... он не говорит ему игнорировать escape-символы, он на самом деле говорит компилятору интерпретировать строку как литерал.

Если у тебя есть

string s = @"cat
             dog
             fish"

на самом деле он будет распечатан как (обратите внимание, что он даже включает пробелы, используемые для отступа):

cat
             dog
             fish
221
12.09.2009 20:33:53
Разве строка не будет включать все пробелы, которые вы использовали для отступа?
andy 13.10.2008 22:39:11
Да, это называется дословной строкой.
Joan Venge 3.03.2009 20:57:21
Было бы яснее, если бы в выходных данных были указаны пробелы, которые также будут распечатаны. Прямо сейчас кажется, что символы новых строк печатаются, но пробелы игнорируются.
aleemb 28.04.2009 11:15:24
Очень полезно для экранирования регулярных выражений и длинных SQL-запросов.
ashes999 21.12.2010 16:07:34
Он также отображает {{на {и }}на что }делает его полезным для string.Format().
Ferruccio 8.01.2012 16:12:28

Две вещи, которые мне нравятся, это свойства Automatic, так что вы можете свернуть свой код еще дальше:

private string _name;
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

становится

public string Name { get; set;}

Также инициализаторы объекта:

Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();

становится

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}
262
13.08.2008 07:39:13
Следует ли отметить, что автоматические свойства являются только функцией C # 3.0?
Jared Updike 18.09.2008 22:53:27
Автоматические свойства были введены с компилятором 3.0. Но поскольку компилятор может быть настроен на вывод кода 2.0, он работает просто отлично. Только не пытайтесь скомпилировать код 2.0 с автоматическими свойствами в старом компиляторе!
Joshua Shannon 10.03.2009 14:59:22
Многие люди не понимают, что get и set могут иметь различную доступность, например: public string Name {get; частный набор;}
Nader Shirazie 13.06.2009 20:27:40
Единственная проблема с автоматическими свойствами заключается в том, что невозможно предоставить значение инициализации по умолчанию.
Stein Åsmul 12.09.2009 20:57:52
@ ANeves: нет, это не так. С этой страницы: DefaultValueAttribute не приведет к автоматической инициализации элемента со значением атрибута. Вы должны установить начальное значение в вашем коде. [DefaultValue]используется для дизайнера, поэтому он знает, показывать ли свойство жирным шрифтом (то есть не по умолчанию).
Roger Lipscombe 14.06.2010 08:24:47

Исходя из того, что этот поток должен называться « вещи, которые вы не знали о C # до недавнего времени, несмотря на то, что думали, что вы уже все знали », моя личная особенность - асинхронные делегаты.

Пока я не прочитал книгу Джеффа Рихтера по C # / CLR (отличная книга, ее должны прочитать все, кто занимается .NET), я не знал, что вы можете вызвать любого делегата с помощью BeginInvoke/ EndInvoke. Я имею тенденцию делать много ThreadPool.QueueUserWorkItemвызовов (что, я думаю, очень похоже на то, что BeginInvokeделает делегат внутри), но иногда может быть действительно полезно добавление стандартизированного шаблона соединения / рандеву.

21
21.03.2011 21:35:52
Да BeginInvoke / EnInvoke использует пул потоков, я узнал об этом на этом форуме. См stackoverflow.com/questions/442991/... и msdn.microsoft.com/en-us/library/2e08f6yc.aspx .
tuinstoel 16.01.2009 17:20:13
«вещи, которые вы не знали о C # до недавнего времени, несмотря на то, что думали, что вы уже все знали» +1
corymathews 4.11.2009 19:44:05

Ключевое слово «default» в универсальных типах:

T t = default(T);

приводит к нулю, если T является ссылочным типом, и 0, если это int, и false, если это логическое значение, и так далее.

255
13.08.2008 10:20:07
Плюс: тип? как ярлык для Nullable <тип>. default (int) == 0, но default (int?) == null.
sunside 24.07.2010 17:22:24

Лямбда-выражения

Func<int, int, int> add = (a, b) => (a + b);

Неизвестные форматы строк

Console.WriteLine("{0:D10}", 2); // 0000000002

Dictionary<string, string> dict = new Dictionary<string, string> { 
    {"David", "C#"}, 
    {"Johann", "Perl"}, 
    {"Morgan", "Python"}
};

Console.WriteLine( "{0,10} {1, 10}", "Programmer", "Language" );

Console.WriteLine( "-".PadRight( 21, '-' ) );

foreach (string key in dict.Keys)
{
    Console.WriteLine( "{0, 10} {1, 10}", key, dict[key] );             
}
13
8.09.2008 17:30:22
Лямбда-выражения объясняются более подробно здесь: developer.com/net/csharp/article.php/3598381 и здесь: msdn.microsoft.com/en-us/library/bb397687.aspx
Ogre Psalm33 15.05.2009 20:16:47

Мне нравится тот факт, что я могу использовать LINQ для объектов в старой версии .NET 2.0 (т.е. без необходимости установки везде .NET 3.5). Все, что вам нужно, это реализация всех методов расширения оператора запроса - см. LINQBridge

11
14.08.2008 10:59:21

В дополнение к ответу duncansmart, в Framework 2.0 могут также использоваться методы расширения. Просто добавьте ExtensionAttributeкласс в пространство имен System.Runtime.CompilerServices, и вы сможете использовать методы расширения (конечно, только в C # 3.0).

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute
    { 
    }
}
7
19.05.2010 15:01:55

Возможность иметь типы перечислений имеют значения, отличные от int (по умолчанию)

public enum MyEnum : long
{
    Val1 = 1,
    Val2 = 2
}

Кроме того, тот факт, что вы можете назначить любое числовое значение этому перечислению:

MyEnum e = (MyEnum)123;
36
14.08.2008 22:31:26
Но ценности должны быть сдержанными. Так что никаких полетов и удваиваний и т. Д. Только ради полноты;)
Boris Callens 23.09.2008 07:24:01
Почему вы хотите иметь возможность присваивать перечислению только старые значения? Не является ли смысл перечисления ограничивать выбор значений?
RobH 8.05.2009 18:51:45
Я считаю, что компилятор должен поддерживать это ради поддержки флагов. Таким образом, с учетом перечисления выше, если вы делаете MyEnum val = MyEnum.Val1 | MyEnum.Val2 вы получите значение, которое находится за пределами уже определенных возможных значений. (в данном случае 3). Поскольку вы можете выполнять двоичную арифметику с перечислениями, теоретически они могут иметь много возможных значений.
Luke Foust 11.05.2009 21:35:36
Одной из причин может быть сопоставление его со столбцом идентификатора таблицы начальной загрузки только для чтения в базе данных.
Aaronaught 17.12.2009 21:59:26
У вас также может быть [Flags], чтобы сказать, что перечисление основано на флаге
SztupY 16.05.2010 11:33:28

Из CLR через C # :

При нормализации строк настоятельно рекомендуется использовать ToUpperInvariant вместо ToLowerInvariant, потому что Microsoft оптимизировала код для сравнения в верхнем регистре .

Я помню, как однажды мой коллега всегда сравнивал строки в верхний регистр перед сравнением. Я всегда удивлялся, почему он это делает, потому что я чувствую, что более «естественно» сначала перевести в нижний регистр. После прочтения книги теперь я знаю почему.

438
15.08.2008 11:06:48
Когда вы «конвертируете строку в верхний регистр», вы создаете второй временный строковый объект. Я подумал, что этот вид сравнения не является предпочтительным, что лучшим способом было: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase), который вообще не создает эту одноразовую строку.
Anthony 23.09.2008 14:44:34
Какую оптимизацию вы можете выполнить при сравнении строк в верхнем регистре, которые нельзя выполнить в строках в нижнем регистре? Я не понимаю, почему один будет более оптимальным, чем другой.
Parappa 24.10.2008 17:38:28
Преобразование в верхний регистр, а не в нижний регистр также может предотвратить некорректное поведение в определенных культурах. Например, на турецком языке две строчные буквы i отображаются на одну заглавную букву I. Google "turkish i" для более подробной информации.
Neil 17.12.2008 17:17:10
Я попытался сравнить ToUpperInvariant с ToLowerInvariant. Я не могу найти никакой разницы в их производительности под .NET 2.0 или 3.5. Конечно, нет ничего, что оправдывало бы «настоятельно рекомендовать» использование одного над другим.
Rasmus Faber 21.01.2009 21:41:59
ToUpperInvariant является предпочтительным, потому что он делает все символы в обоих направлениях. См. Msdn.microsoft.com/en-us/library/bb386042.aspx . Для сравнения напишите"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks 4.06.2009 19:35:57

Мой любимый это

global::

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

Пример:

global::System.Collections.Generic.List<global::System.String> myList =
    new global::System.Collections.Generic.List<global::System.String>();
33
7.06.2011 17:44:40
Он работает так же, как спецификатор доступа, но в отношении пространств имен, то есть globalпри использовании с квалификатором псевдонима пространства имен ::ссылается на глобальное пространство имен, которое является пространством имен по умолчанию для любой программы на C #. Пример использования здесь - msdn.microsoft.com/en-us/library/c3ay4x3d.aspx
Robin Maben 13.12.2010 09:17:50

Я не начал по-настоящему ценить блоки "использования" до недавнего времени. Они делают вещи намного более аккуратными :)

13
15.08.2008 14:51:42

Этот не «спрятан» так, как его неправильно назвали.

Большое внимание уделяется алгоритмам «карта», «уменьшить» и «фильтр». Большинство людей не осознают, что в .NET 3.5 добавлены все три из этих алгоритмов, но он дал им очень SQL-имена, основываясь на том факте, что они являются частью LINQ.

"map" => Выбрать.
Преобразует данные из одной формы в другую.

"Reduce" => агрегировать
агрегирует значения в один результат

"filter" => Где
Фильтрует данные на основе критериев

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

116
16.08.2008 23:55:28
Select также действует как функция возврата в монадах. См. Stackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade 1.01.2009 16:15:33
Использование «select» необходимо только в том случае, если вы используете синтаксис SQLish. Если вы используете синтаксис метода расширения - someCollection.Where (item => item.Price> 5.99M) - использование операторов выбора не требуется.
Brad Wilson 1.04.2010 18:41:33
@Brad, это (где) является операцией фильтра. Попробуйте выполнить операцию с картой без выбора ...
Eloff 10.05.2010 22:31:53
По моему мнению, LINQ - это большая вещь, которая произошла с C #: stackoverflow.com/questions/2398818/…
Leniel Maccaferri 29.05.2010 20:53:28
Наименьшая сигнатура агрегата - это функция «уменьшить», средняя сигнатура агрегата - гораздо более мощная функция «складывания»!
Brett Widmeier 14.03.2011 22:50:54