Приховані особливості C #? [зачинено]


1475

Це мені прийшло в голову після того, як я дізнався наступне з цього питання :

where T : struct

Ми, розробники C #, всі знаємо основи C #. Я маю на увазі декларації, умовні умови, цикли, оператори тощо.

Деякі з нас навіть освоїли такі речі, як Generics , анонімні типи , лямбда , LINQ , ...

Але які найпотаємніші особливості або хитрощі C #, про які навіть фанати C #, наркомани, експерти майже не знають?

Ось розкриті до цього часу функції:


Ключові слова

Атрибути

Синтаксис

Мовні особливості

Особливості візуальної студії

Рамка

Методи та властивості

Поради та рекомендації

  • Хороший метод для організаторів подій Andreas HR Nilsson
  • Великі порівняння Джона
  • Отримайте доступ до анонімних типів без відображення dp
  • Швидкий спосіб Ліниво властивостей колекції Instantiate по Волі
  • JavaScript-подібні анонімні вбудовані функції від roosteronacid

Інший

Відповіді:


752

Це не C # per se, але я не бачив нікого, хто насправді використовує System.IO.Path.Combine()в тій мірі, в якій повинен. Насправді весь клас Path насправді корисний, але його ніхто не використовує!

Я готовий зробити ставку, що кожен додаток для виробництва має наступний код, навіть якщо він не повинен:

string path = dir + "\\" + fileName;

584

лямбда і типи умовиводів недооцінені. У Lambdas може бути кілька заяв, і вони автоматично подвоюються як сумісний об’єкт делегата (просто переконайтеся, що підпис відповідає) як у:

Console.CancelKeyPress +=
    (sender, e) => {
        Console.WriteLine("CTRL+C detected!\n");
        e.Cancel = true;
    };

Зауважте, що я не маю new CancellationEventHandlerані, я не повинен вказувати типи, senderі eвони можуть бути зарахованими від події. Ось чому це менш громіздко писати ціле, delegate (blah blah)що також вимагає вказати типи параметрів.

Лямбдам нічого не потрібно повертати, а умовивід є надзвичайно потужним у подібному контексті.

І BTW, ви завжди можете повернути Lambdas, що робить Lambdas у сенсі функціонального програмування. Наприклад, ось лямбда, яка робить лямбда, яка обробляє подію Button.Click:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

Зверніть увагу на ланцюжок: (dx, dy) => (sender, e) =>

Тепер я радий взяти клас функціонального програмування :-)

Окрім покажчиків на С, я думаю, що це інша фундаментальна річ, якій ви повинні навчитися :-)


528

Від Ріка Штраля :

Ви можете ланцюг ?? оператора, щоб ви могли здійснити купу нульових порівнянь.

string result = value1 ?? value2 ?? value3 ?? String.Empty;

454

Псевдонімічні дженерики:

using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;

Це дозволяє використовувати ASimpleNameзамість цього Dictionary<string, Dictionary<string, List<string>>>.

Використовуйте його, коли б ви використовували ту саму загальну велику довгу складну річ у багатьох місцях.


438

З CLR через C # :

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

Пам’ятаю, колись мій колега завжди міняв рядки на великі регістри перед порівнянням. Мені завжди було цікаво, чому він це робить, тому що я вважаю, що це "природніше" спочатку перетворитись на малі регістри. Прочитавши книгу зараз я знаю, чому.


254
Коли ви "конвертуєте рядок у верхній регістр", ви створюєте другий тимчасовий рядковий об'єкт. Я думав, що подібне порівняння не є кращим, а найкращим способом є: String.Equals (stringA, stringB, StringComppare.CurrentCultureIgnoreCase), який взагалі не створює цю викидну рядок.
Ентоні

32
Яку оптимізацію можна виконати для порівняння верхніх рядків рядків, які неможливо виконати на нижньому регістрі? Я не розумію, чому один був би більш оптимальним, ніж інший.
Параппа

36
Перетворення на великі, а не малі регістри також може запобігти неправильній поведінці в певних культурах. Наприклад, на турецькій мові дві малі i карти на ту саму верхню регістр I. Google "turkish i" для отримання детальної інформації.
Ніл

34
Я спробував порівняльний аналіз ToUpperInvariant проти ToLowerInvariant. Я не можу знайти різниці в їх продуктивності під .NET 2.0 або 3.5. Безумовно, немає нічого, що вимагає "високо рекомендуючого" використання одного над іншим.
Расмус Фабер

19
ToUpperInvariant є кращим, оскільки він змушує всіх символів в обидва кінці. Див. Msdn.microsoft.com/en-us/library/bb386042.aspx . Для порівняння пишіть"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks

408

Моя улюблена хитрість - використання оператора null coalesce та круглих дужок для автоматичної інстанцізації колекцій для мене.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }

23
Вам не важко читати?
Рірі

72
Його трохи важко читати для ноо ... ер, недосвідчений. Але він компактний і містить пару моделей та мовних особливостей, які програміст повинен знати та розуміти. Тож, хоча спочатку важко, це дає перевагу бути приводом для навчання.

38
Ледача інстанція дещо недосконала, тому що це поганий вибір чоловіків, щоб не думати про класові інваріанти. Він також має проблеми з одночасністю.
Джон Лейдегрен

17
Мені завжди було відомо, що це погана практика, що виклик власності не повинен робити щось таке. Якщо у вас там був набір і встановив значення "null", це було б дуже дивно для тих, хто використовує ваш API.
Ян

8
@Joel, за винятком того, що встановлення ListOfFoo на нуль не є частиною класового контракту, а також не є доброю практикою. Тому не існує сеттера. Це також тому, що ListOfFoo гарантовано поверне колекцію і ніколи не буде нульовою. Це дуже дивна скарга на те, що якщо ви зробите дві погані речі (зробите сетер і встановите колекцію на нуль), це призведе до того, що ваші очікування помиляються. Я також не пропоную робити Environment.Exit () в Getter. Але це також не має нічого спільного з цією відповіддю.

315

Уникайте перевірки наявних обробників подій

Додавання порожнього делегата до подій під час декларування, придушення необхідності завжди перевіряти подію на нуль, перш ніж називати її дивним. Приклад:

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");
    }
}

Будь ласка, також дивіться цю пов’язану дискусію та цю публікацію в блозі Еріка Ліпперта на цю тему (та можливі мінуси).


87
Я вважаю, що проблема з’явиться, якщо ви покладаєтесь на цю техніку і тоді вам доведеться серіалізувати клас. Ви усунете подію, а потім при десеріалізації ви отримаєте NullRefference .... Це безпечніше.
sirrocco

16
Ви все одно можете встановити обробник подій на нуль, так що ви все одно можете отримати нульову посилання, і ви все ще маєте умови гонки.
Роберт Полсон,

64
Швидкий тест профілю показує, що обробник подій, підписаний на манекен, без нульового тестування займає приблизно в 2 рази час скасування підписки на обробку подій з нульовим тестом. Обробник подій для багатоадресної передачі без нульового тесту займає приблизно 3,5 рази час обробника події одиночної події з нульовим тестом.
P тато

54
Це дозволяє уникнути необхідності проведення нульової перевірки, якщо завжди мати самостійного абонента. Навіть як порожня подія це несе накладні витрати, яких ви не хочете. Якщо немає передплатників, ви взагалі не хочете запускати подію, не завжди спочатку запускайте порожню підроблену подію. Я вважав би це поганим кодом.
Кіт

56
Це жахлива пропозиція, з причин у вищезазначених коментарях. Якщо ви повинні зробити свій код "чистим", використовуйте метод розширення, щоб перевірити наявність нуля, а потім викликайте подію. Хтось із привілеями модифікувати обов'язково повинен додати мінуси до цієї відповіді.
Грег

305

Все інше, плюс

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();

14
в №3 ви можете зробити Enumerable.Range (1,5)
Echostorm

18
я думаю, вам вдалося ініціалізувати масиви з int [] nums = {1,2,3}; оскільки 1.0 :) навіть не потребує "нового" ключового слова
Лукас

13
також лямбда без параметрів () => DoSomething ();
Пабло Ретик

5
Я використовував обидва {get; внутрішній набір; } і {дістати; захищений набір; }, тому ця закономірність узгоджується.
Кіт

7
@Kirk Broadhurst - ти маєш рацію - new web.Control()також би працював у цьому прикладі. У ::синтаксичних змушує його лікувати префікс як псевдонім простору імен, так що ви могли б мати клас з ім'ям webі web::Controlсинтаксис буде по- , як і раніше працювати, в той час як web.Controlсинтаксис не знатиме , перевіряти чи клас або простір імен. Через це я прагну завжди використовувати ::псевдоніми простору імен.
Кіт

286

Я не знав ключового слова "як" досить довго.

MyClass myObject = (MyClass) obj;

проти

MyClass myObject = obj as MyClass;

Другий поверне null, якщо obj не MyClass, а не кине виняток з класу.


42
Не перестарайтеся, хоча. Багато людей, здається, використовують так, тому що віддають перевагу синтаксису, хоча вони хочуть семантику (ToType) x.
Скотт Ленгем,

4
Я не вірю, що це забезпечує кращі показники. Ви це профілювали? (Очевидно, що це робиться, коли акторський склад провалюється ... але коли ви використовуєте (MyClass) ролик, збої є винятковими .. і надзвичайно рідкісними (якщо вони взагалі трапляються), тому це не має ніякого значення.
Скотт Ленґем

7
Це лише більш ефективно, якщо звичайний випадок - це невдалий склад. В іншому випадку об'єкт прямого відтворення (тип) відбувається швидше. Для прямого амплуа, щоб викинути виняток, потрібно довше, ніж для повернення нуля.
Спенс

15
Прямо вздовж тих же рядків ключового слова "як" ... ключове слово "є" так само корисно.
dkpatt

28
Ви можете зловживати цим і мати NullReferenceException по дорозі пізніше, коли ви могли раніше мати InvalidCastException.
Андрій Ронеа

262

Дві речі, які мені подобаються, - це автоматичні властивості, щоб ви могли ще більше згортати код:

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()}

6
Чи слід зазначити, що автоматичні властивості - це лише функція C # 3.0?
Jared Updike

21
Автоматичні властивості були представлені компілятором 3.0. Але оскільки компілятор може бути встановлений для виведення коду 2.0, вони працюють просто чудово. Просто не намагайтеся компілювати 2.0 код з автоматичними властивостями у старшому компіляторі!
Джошуа Шеннон

74
Що багато хто не усвідомлює, це те, що отримати і встановити може мати різну доступність, наприклад: public string Name {get; приватний набір;}
Надер Ширазі

7
Єдина проблема з автоматичними властивостями полягає в тому, що, здається, неможливо надати значення ініціалізації за замовчуванням.
Stein Åsmul

7
@ANeves: ні, це не так. З цієї сторінки: DefaultValueAttribute не призведе до автоматичного ініціалізації учасника зі значенням атрибута. Ви повинні встановити початкове значення у своєму коді. [DefaultValue]використовується для дизайнера, тому він знає, чи слід показувати властивість жирним шрифтом (мається на увазі не за замовчуванням).
Роджер Ліпскомб

255

Ключове слово "за замовчуванням" у загальних типах:

T t = default(T);

приводить до "null", якщо T є еталонним типом, і 0, якщо це int, false, якщо це булева, etcetera.


4
Плюс: тип? як ярлик для Nullable <type>. default (int) == 0, але за замовчуванням (int?) == null.
вранці


221

@ Повідомляє компілятору ігнорувати будь-які символи в рядку.

Просто хотів уточнити цей ... він не говорить йому проігнорувати символи втечі, він фактично підказує компілятору інтерпретувати рядок як буквальний.

Якщо у вас є

string s = @"cat
             dog
             fish"

він фактично буде роздруковуватися як (зауважте, що він включає навіть пробіл, який використовується для відступу):

cat
             dog
             fish

Чи не містить рядок усі пробіли, які використовувались для відступу?
andy

18
Так, це називається дослівно-рядковим рядком.
Джоан Венге

4
Було б зрозуміліше, якби на виході показано пробіли, які також будуть надруковані. Зараз здається, що нові символи рядків друкуються, але пробіли ігноруються.
aleemb

Дуже корисно для уникнення регулярних виразів та довгих SQL-запитів.
ashes999

Він також відображає {{на {і }}на що }робить його корисним для string.Format().
Ферруччо

220

Я думаю, що однією з найбільш недооцінених і менш відомих особливостей C # (.NET 3.5) є дерева виразів , особливо в поєднанні з Generics і Lambdas. Це підхід до створення API, який використовують новіші бібліотеки, такі як NInject і Moq.

Наприклад, скажімо, що я хочу зареєструвати метод з API, і API потрібно отримати ім'я методу

Враховуючи цей клас:

public class MyClass
{
     public void SomeMethod() { /* Do Something */ }
}

Раніше розробникам було дуже часто бачити, як це роблять за допомогою рядків і типів (або чогось іншого, що значною мірою на основі рядків):

RegisterMethod(typeof(MyClass), "SomeMethod");

Ну, це смокче через відсутність сильного набору тексту. Що робити, якщо я перейменую "SomeMethod"? Тепер, у 3.5, я можу це зробити напевно:

RegisterMethod<MyClass>(cl => cl.SomeMethod());

У якому клас RegisterMethod використовує Expression<Action<T>>так:

void RegisterMethod<T>(Expression<Action<T>> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

Це одна з головних причин того, що я зараз закоханий у лямбда і виразних дерев.


3
У мене є клас утиліти відображення, який робить те саме з FieldInfo, PropertyInfo тощо ...
Олмо,

Так, це чудово. Мені вдалося використовувати такі методи, як писати код, як EditValue(someEmployee, e => e.FirstName);у моїй бізнес-логіці, і він автоматично генерував всю логіку сантехніки для ViewModel і View для редагування цього властивості (так, мітка з текстом "Ім'я" та TextBox з прив'язка, яка викликає сеттера властивості FirstName, коли користувач редагує ім'я та оновлює представлення даних за допомогою getter). Це, мабуть, є основою для більшості нових внутрішніх DSL в C #.
Скотт Вітлок

4
Я думаю, що вони не так маловідомі, як менш зрозумілі.
Джастін Морган

Чому потрібно зареєструвати метод? Я ніколи раніше цього не використовував - де і коли це було б використано?
MoonKnight

209

« урожайність » прийшла б мені на думку. Деякі з атрибутів, таких як [DefaultValue ()] , також є серед моїх улюблених.

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

Редагувати: kokos, дякую за вказівку ?? Оператор, це дійсно корисно. Оскільки для нього трохи важко google (оскільки ?? просто ігнорується), ось сторінка документації MSDN для цього оператора: ?? Оператор (довідка C #)


14
Документація значення за замовчуванням говорить, що це насправді не встановлення значення властивості. Це лише помічник для візуалізаторів та генераторів коду.
Борис Калленс

2
Щодо DefaultValue: Тим часом деякі бібліотеки використовують його. ASP.net MVC використовує DefaultValue для параметрів дії контролера (що дуже корисно для ненульових типів). Строго кажучи, звичайно, це генератор коду, оскільки значення встановлюється не компілятором, а кодом MVC.
Майкл Штум

6
Назва для ?? оператор - оператор "Null Coalescing"
Armstrongest

урожай - мій улюблений, хоч оператор злиття там, хоча. Я нічого не бачу щодо CAS, або підписання збірки, сильних імен, GAC ... Я вважаю, що лише CAS - це C # ..., але так багато розробників не мають поняття про безпеку.
BrainSlugs83

198

Я схильний вважати, що більшість розробників C # не знають про "нульові" типи. В основному, примітиви, які можуть мати нульове значення.

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

Встановіть нульовий подвійний, num1 , null, а потім встановіть звичайний double, num2 , num1 або -100, якщо num1 було null.

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

ще одна річ про тип Nullable:

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

це повернення String.Empty. Перевірте це посилання для отримання більш детальної інформації


1
DateTime не можна встановити на нуль.
Джейсон Джексон

2
Тож тоді "int" просто синтаксичний цукор C # для System.Int32? Насправді є підтримка компілятора, побудована навколо типів Nullable, що дозволяє встановити їх на нуль, наприклад (що неможливо зробити лише за допомогою загальних структур), і позначає їх як їх базовий тип.
P тато

4
@P Daddy - так, int - синтаксичний цукор для System.Int32. Вони повністю взаємозамінні, як і Int? === Int32? === Nullable <Int32> === Nullable <int>
cjk

6
@ck: Так, int є псевдонімом для System.Int32, як T? псевдонім Nullable <T>, але це не просто синтаксичний цукор. Це визначена частина мови. Псевдоніми не тільки полегшують читання коду, але й краще відповідають нашій моделі. Виражаючи Nullable <Double> як подвійний? підкреслює точку зору, що міститься таким чином значення є (або може бути) подвійним, а не лише деякою родовою структурою, інстанційованою на тип Double. (продовження)
P тато

3
... У будь-якому випадку, аргумент полягав не в псевдонімах (я думаю, це була лише погана аналогія, я думаю, що), але такі мінливі типи - використовуючи синтаксис, який ви хочете - справді є мовною особливістю, а не лише продуктом генерики. Ви не можете відтворити всю функціональність змінних (порівняння до / присвоєння нуля, переадресація оператора, бокс базового типу або нуля, сумісність з об'єднанням нулів та asоператорами) лише з генеричними файлами. Поняття Nullable <T> є рудиментарним та далеко не зоряним, але концепція змінних типів як частини мови - кіт.
P тато

193

Ось кілька цікавих прихованих функцій C # у вигляді недокументованих ключових слів C #:

__makeref

__reftype

__refvalue

__arglist

Це недокументовані ключові слова C # (навіть Visual Studio їх розпізнає!), Які були додані для більш ефективного боксу / розпакування перед дженериками. Вони працюють узгоджено з системою System.TypedReference.

Є також __arglist, який використовується для списків параметрів змінної довжини.

Одне, про що люди мало знають - це System.WeakReference - дуже корисний клас, який відслідковує об’єкт, але все ще дозволяє сміттєзбірнику збирати його.

Найбільш корисною "прихованою" функцією буде ключове слово повернення доходу. Це насправді не приховано, але багато людей не знають про це. LINQ побудований поверх цього; він дозволяє проводити запити, що виконуються затримкою, генеруючи державний апарат під кришкою. Нещодавно Реймонд Чен розмістив інформацію про внутрішні, жаркі деталі .


2
Детальніше про недокументовані ключові слова Пітера Бромберга . Я все ще не розумію, якщо є причини коли-небудь використовувати їх.
HuBeZa

@HuBeZa з появою дженериків, не так багато (будь-яких?) Вагомих причин для використання __refType, __makeref та __refvalue. Вони використовувалися головним чином, щоб уникнути боксу до дженериків у .NET 2.
Іуда Габріель Хіманго

Метт, з впровадженням дженериків у .NET 2 мало підстав використовувати ці ключові слова, оскільки їх метою було уникнути боксу при роботі із типами значень. Дивіться посилання від HuBeZa, а також дивіться codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Іуда Габріель Хіманго

185

Союзи (C ++ вид спільної пам'яті) в чистому, безпечному C #

Не вдаючись до небезпечного режиму та покажчиків, ви можете змусити членів класу поділяти простір пам’яті в класі / структурі. Дано наступний клас:

[StructLayout(LayoutKind.Explicit)]
public class A
{
    [FieldOffset(0)]
    public byte One;

    [FieldOffset(1)]
    public byte Two;

    [FieldOffset(2)]
    public byte Three;

    [FieldOffset(3)]
    public byte Four;

    [FieldOffset(0)]
    public int Int32;
}

Ви можете змінювати значення байтових полів, маніпулюючи полем Int32 і навпаки. Наприклад, ця програма:

    static void Main(string[] args)
    {
        A a = new A { Int32 = int.MaxValue };

        Console.WriteLine(a.Int32);
        Console.WriteLine("{0:X} {1:X} {2:X} {3:X}", a.One, a.Two, a.Three, a.Four);

        a.Four = 0;
        a.Three = 0;
        Console.WriteLine(a.Int32);
    }

Виводи це:

2147483647
FF FF FF 7F
65535

просто додати за допомогою System.Runtime.InteropServices;


7
@George, творить чудеса, коли ви спілкуєтеся зі застарілими програмами через сокети, використовуючи c-об’єднання декларацій.
scottm

2
Тут також є сенс сказати int та float при зміщенні 0. Це те, що вам потрібно, якщо ви хочете маніпулювати числами з плаваючою комою як бітові маски, чого іноді хочете. Особливо, якщо ви хочете дізнатися нові речі про числа з плаваючою комою
Джон Лейдегрен

2
Прикро це в тому, що якщо ви збираєтеся використовувати цю структуру, компілятор змусить вас встановити ВСІ змінні у функції init. Отже, якщо у вас є: public A (int int32) {Int32 = int32; } він буде кидати "Поле" Один "має бути повністю призначене до повернення абоненту", тому вам доведеться встановити Один = Два = Три = Чотири = 0; так само.
manixrock

2
Це має своє використання, переважно з бінарними даними. Я використовую структуру "Pixel" з int32 @ 0 і чотирма байтами для чотирьох компонентів @ 0, 1, 2 та 3. Чудово підходить для швидкого та легкого управління даними зображення.
snarf

57
Попередження: Цей підхід не враховує витривалість. Це означає, що ваш C # код не працюватиме однаково на всіх машинах. На процесорах з малим ендіанським процесором (які зберігають перший найменш значущий байт) буде використано показану поведінку. Але на великих процесорах великих байтів байти вийдуть із того, що ви очікували. Остерігайтеся того, як ви використовуєте це у виробничому коді - ваш код може не переноситися на певні мобільні пристрої та інше обладнання та може ламатися неочевидними способами (наприклад, два файли, нібито в тому ж форматі, але насправді з переверненим порядком байтів).
Рей Бернс

176

Використання @ для імен змінних, які є ключовими словами.

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 

38
Чому ви хочете використовувати ключове слово як ім'я змінної? Мені здається, що це зробить код менш читабельним і неясним.
Джон

41
Ну, причина в тому, що CLI вимагає цього для сумісності з іншими мовами, які можуть використовувати ключові слова C # як імена учасників
Марк Cidade,

69
Якщо ви коли-небудь хотіли скористатися HTML-помічниками asp.net MVC та визначити HTML-клас, ви будете раді дізнатись, що ви можете використовувати @class, тому він не буде визнаний ключовим словом класу
Борис Келленс,

31
Відмінно підходить для методів розширення. публічна статична порожнеча DoSomething (ця смужка @ це, рядок) {...}
Джонатан С Дікінсон

45
@zihotki: Неправильно. var a = 5; Console.WriteLine (@a);
Друки

168

Якщо ви хочете вийти зі своєї програми, не викликаючи остаточних блоків або фіналізаторів, використовуйте FailFast :

Environment.FailFast()

12
Зауважте, що цей метод також створює дамп пам'яті та записує повідомлення в журнал помилок Windows.
RickNZ

1
Слід зазначити, що при використанні цього методу не буде викликано жодних фіналізаторів чи подій завантаження домену додатків ...
AwkwardCoder

1
+1 для підказки, але це не C #, це BCL .NET.
Авель

System.Diagnostics.Process.GetCurrentProcess (). Вбити () швидше
Tolgahan Albayrak

153

Повернення анонімних типів із методу та доступ до членів без роздумів.

// Useful? probably not.
private void foo()
{
    var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
    Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}

object GetUserTuple()
{
    return new { Name = "dp", Badges = 5 };
}    

// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
   return (T) obj;
}

42
Це насправді нічого не отримує. Це насправді небезпечно. Що робити, якщо GetUserTuple змінено для повернення декількох типів? Час виступу буде невдалим. Однією з чудових речей про C # /. Net є перевірка часу компіляції. Набагато краще було б просто створити новий тип.
Джейсон Джексон

9
@Jason Я сказав, що це, мабуть, не корисно, але це дивно (і я думав, що це приховано).
denis phillips

31
Хоча це круто, це здається досить поганим вибором дизайну. Ви в основному визначили анонімний тип у двох місцях. У цей момент просто оголосити справжню структуру та використовувати її безпосередньо.
Пол Олександр

6
@George: таку конвенцію можна назвати ... структурою?
Р. Мартіньо Фернандес

2
цей трюк має назву "відібраний за зразком", і він не працюватиме, якщо метод, який повертає анонімний тип, знаходиться в іншій збірці.
desco

146

Ось корисний для регулярних виразів та шляхів до файлів:

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

@ Повідомляє компілятору ігнорувати будь-які символи в рядку.


27
Також константа @ приймає нові рядки всередині. Ідеально підходить при призначенні багаторядкового сценарію до рядка.
Tor Haugen

11
Не забудьте також уникнути лапки, просто подвоїти їх, іншими словами. [code] var candy = @ "Мені подобається" "червоний" "цукеркові тростини."; [/ code]
Дейв

5
Я схильний будувати шляхи за допомогою Path.Combine. Я обов'язково використовую @ для regex!
Ден МакКлейн

6
@new - це також змінна, а не ключове слово: @this, @int, @return, @interface ... так далі :)
IАнотація

Ця людина ніде не підходить: Але які найпотаємніші риси та хитрощі C #, які навіть фанати C #, наркомани, експерти майже не знають?
publicgk

141

Міксини. Якщо ви хочете додати функцію до декількох класів, але не можете використовувати один базовий клас для всіх, отримайте кожен клас для реалізації інтерфейсу (без членів). Потім запишіть метод розширення для інтерфейсу , тобто

public static DeepCopy(this IPrototype p) { ... }

Звичайно, деяка ясність приносять у жертву. Але це працює!


4
Так, я думаю, це справжня сила методів розширення. Вони в основному дозволяють реалізувати методи інтерфейсу.
Іван Бубріскі

Це також зручно, якщо ви використовуєте NHibernate (або Castle ActiveRecord) і вам потрібно використовувати інтерфейси для своїх колекцій. Таким чином ви можете надавати поведінку інтерфейсам колекції.
Райан Лунді

Це, як правило, всі методи LINQ реалізовані для запису.
WCWedin

Ось посилання, що розповідає про те, про що я згадував вище, використовуючи методи розширення з інтерфейсами колекції в NHibernate або Castle ActiveRecord: devlicio.us/blogs/billy_mccafferty/archive/2008/09/03/…
Ryan Lundy

7
Якби вони дозволяли властивості розширення !!!! Я ненавиджу писати метод розширення, який просив бути властивістю лише для читання ....
Джон Гібб

130

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

Правда, помилково, FileNotFound ?


87
якщо ви очікуєте, що користувач відповість "так ні", тоді нульова відповідь буде, якщо на це питання не було відповіді
Омар Кохеджі

22
Зменшувані типи зручні для взаємодії з базою даних, де стовпці таблиць часто є нульовими.
tuinstoel

11
Так, ні, Майе?
Ден Блер

21
Збережіть значення CheckShore ThreeState
Shimmy Weitzhandler

8
Як у SQL: Так / ні / невідомо.
erikkallen

116

Цей не так «прихований», як його неправильно називають.

Багато уваги приділяється алгоритмам «карта», «зменшення» та «фільтр». Більшість людей не розуміє, що .NET 3.5 додав усі три алгоритми, але він дав їм дуже імена SQL-ish, виходячи з того, що вони є частиною LINQ.

"map" => Вибрати
Перетворити дані з однієї форми в іншу

"зменшити" => Сукупність
Об'єднати значення агрегування в єдиний результат

"filter" => Де фільтрує
дані на основі критеріїв

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


1
Вибір також діє як функція "повернення" в монадах. Дивіться stackoverflow.com/questions/9033/hidden-features-of-c#405088
Марк Сідаде

1
Використовувати "select" потрібно лише в тому випадку, якщо ви використовуєте синтаксис SQLish. Якщо ви використовуєте синтаксис методу розширення - someCollection.Where (item => item.Price> 5.99M) - використання операторів select не потрібно.
Бред Вілсон

7
@Brad, що (де) - це операція фільтра. Спробуйте зробити операцію з картою без вибору ...
Eloff,

2
LINQ є великий , що трапилося з C # на мій погляд: stackoverflow.com/questions/2398818 / ...
Leniel Маккаферрі

1
Найменший підпис агрегату - це функція "зменшити", середня підпис агрегат - набагато потужніша функція "складання"!
Бретт Відм'єр

115
Environment.NewLine

для системних незалежних нових рядків.


10
Прикра в цьому - те, що він не входить в компактну рамку.
Stormenet

14
Варто зазначити, що це специфічно для платформи хоста програми - тому, якщо ви створюєте дані, призначені для іншої системи, вам слід використовувати \ n або \ r \ n відповідним чином.
Меш

Це частина BCL .NET, а не особливість C # per se.
Авель

111

Якщо ви намагаєтесь використовувати фігурні дужки у виразі String.Format ...

int foo = 3;
string bar = "blind mice";
String.Format("{{I am in brackets!}} {0} {1}", foo, bar);
//Outputs "{I am in brackets!} 3 blind mice"

19
@Kyralessa: Насправді, так, це брекети, але "фігурні дужки" - це альтернативна назва для них. [і ]є квадратними дужками, <і >є кутовими дужками. Дивіться en.wikipedia.org/wiki/Bracket .
icktoofay

4
Ви праві. Але коли я коментував, це не говорило "фігурних" дужок.
Райан Лунді

2
Дуже приємно вказати. Згадайте мій перший String.Format виглядав так: String.Format ("{0} Я в фігурних дужках {1} {2} {3}", "{", "}", 3, "сліпі миші"); Як тільки я дізнався, що уникнути цих проблем робиться за допомогою {{and}} Я був такий щасливий :)
Гертян

Muahahahaa ... Програмування вже 3 роки в. Нет, і я цього не знав. : D
Арніс Лапса

"фігурні" дужки, що діють схожими на послідовності виходу
Пратік

104
  1. ?? - оператор злиття
  2. using ( заява / директива ) - відмінне ключове слово, яке можна використовувати не просто для виклику Dispose
  3. тільки читати - слід використовувати більше
  4. мережеві модулі - дуже погано, що у Visual Studio немає підтримки

6
також можна використовувати для псевдоніму довгий простір імен більш зручному рядку, тобто: використання ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; Тут більше тут: msdn.microsoft.com/en-us/library/sf0df423.aspx
Дейв Р.

2
Це насправді не те саме. Під час виклику Dispose ви можете використовувати оператор, що використовує, під час чищення типів ви використовуєте директиву використання.
Øyvind Skaar

2
На всякий випадок, якщо ви хочете, щоб ім’я було №1 (як ви робили з потрійним оператором), ?? називається оператором злиття нуля.
Дж. Стін

4
@LucasAardvark: Як згадував Дж. Стійн, його називають оператором нульового згортання. Шукайте це!
kokos

1
Шукати ?? Оператор у google спробуйте: google.com/search?q=c%23+%3F%3F+operator
зворотна коса 17

103

@Ed, я трохи стриманий щодо розміщення цього запису, оскільки це трохи більше, ніж випивати. Однак я зазначу, що у вашому зразку коду:

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

Якщо ви збираєтесь використовувати "є", навіщо слідкувати за ним у безпечному ролях, використовуючи "as"? Якщо ви переконалися, що obj - це справді MyClass, болотний стандартний склад:

c = (MyClass)obj

... ніколи не вийде з ладу.

Так само можна сказати:

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

Я не знаю достатньо про внутрішні нутри .NET, щоб бути впевненим, але мої інстинкти говорять мені, що це дозволить скоротити максимум двох типів операцій накидання до максимуму. Навряд чи вдасться зламати обробний банк в будь-якому випадку; особисто я думаю, що остання форма теж виглядає більш чистою.


16
Якщо амплітуда має точний тип (присвоєно "A", коли об'єктом є "A", а не похідне від нього), прямий каст на ~ 3x Швидше, ніж "as". Під час виведення похідного типу (присвоєний "A", коли об'єктом є "B", що походить від "A"), прямий виступ на 0,1% повільніше, ніж "як". "є", тоді "як" просто нерозумно.
P тато

2
Ні, але ви можете написати "if ((c = obj як MyClass)! = Null)".
Дейв Ван ден Ейнде

10
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.
Адам Лютер

2
У IL, переклад переходить до CASTCLASS, але як / є до інструкції ISINST.
Джон Гібб

5
Я побіг тест для цього, лиття IEnumerable<int>в List<int>і лиття object( new object()) для того IEnumerable<int>, щоб переконатися , що немає ніяких помилок: прямий кидка: 5.43ns, IS - > литого: 6.75ns, як кидок: 5.69ns. Потім тестування недійсних ролей: прямий ролик: 3125000сн, як литий: 5,41сн. Висновок: перестаньте турбуватися про коефіцієнт 1%, і просто переконайтеся, що ви використовуєте / як тоді, коли трансляція може бути недійсною, спричиняйте винятки (також якщо їх обробляти) ДУЖЕ повільно порівняно з кастингом, ми говоримо про коефіцієнт 578000 повільніше. Пам’ятайте, що остання частина, решта не має значення (.Net FW 4.0, версія випуску)
Aidiakapi

98

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

if (x == 1)
{
   x = 2;
}
else
{
   x = 3;
}

може бути конденсований до:

x = (x==1) ? 2 : 3;

10
Трійкового оператора заборонили в моїй групі. Деяким людям це просто не подобається, хоча я ніколи не розумів, чому.
Джастін Р.

13
Я здогадуюсь, тому що вони не однакові речі, будучи оператором, а не заявою. Я вважаю за краще перший підхід сам. Він більш стійкий і легко розширюється. Оператори не можуть містити заяви, тому в хвилину розгортання тіла вам доведеться перетворити цього потрійного оператора в оператор if
kervin

16
може бути конденсований до x ++; Гаразд безглуздо ^^
Франсуа

5
@Guillaume: для обліку всіх значень x: x = 2 + System.Math.Min (1, System.Math.Abs ​​(x-1));
mbeckish

38
Це на насправді називається «умовним оператором» - це потрійний оператор , оскільки він приймає три аргументи. en.wikipedia.org/wiki/Conditional_operator
Blorgbeard вийшов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.