Скрытые особенности С#?

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

where T : struct

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

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

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

Вот раскрытые возможности:


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

Атрибуты

Синтаксис

  • ?? (coalesce nulls) оператор kokos
  • Знаки числа Ник Берарди
  • where T:new Lars Mæhlum
  • Неявные дженерики Keith
  • Однопараметрические лямбды Keith
  • Авто свойства Keith
  • Имена псевдонимов Keith
  • Вербатные строковые литералы с @by Patrick
  • enum значения lfoust
  • @variablenames marxidad
  • event операторы marxidad
  • Форматировать скобки строки Портман
  • Модификаторы доступности доступа к ресурсам по xanadont
  • Условный (тройной) оператор (?:) на JasonS
  • checked и unchecked операторы Binoj Antony Операторы
  • implicit and explicit Флори

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

Возможности Visual Studio

  • Выберите блок текста в редакторе Himadri
  • Фрагменты DannySmurf

Структура

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

Советы и рекомендации

  • Хороший метод для обработчиков событий Andreas H.R. Nilsson
  • Сравнение с верхним регистром John
  • Доступ к анонимным типам без отражения dp
  • Быстрый способ ленивого создания свойств коллекции Будет
  • JavaScript-подобные анонимные встроенные функции roosteronacid

Другие

1476
задан Serhat Ozgel 12 авг. '08 в 19:32
источник поделиться
296 ответов

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

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

string path = dir + "\\" + fileName;
752
ответ дан ageektrapped 13 авг. '08 в 4:53
источник поделиться

lambdas и тип inferrence недооцениваются. Lambdas может иметь несколько операторов, и они удваиваются как совместимый объект-делегат автоматически (просто убедитесь, что подпись соответствует), как в:

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

Обратите внимание, что у меня нет new CancellationEventHandler, и я не должен указывать типы sender и e, они выводятся из события. Вот почему это менее громоздко для записи всего delegate (blah blah), в котором также требуется указать типы параметров.

Lambdas не нужно возвращать что-либо, а вывод типа чрезвычайно силен в таком контексте.

И 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) =>

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

Помимо указателей на C, я думаю, что это другая фундаментальная вещь, которую вы должны изучить: -)

585
ответ дан chakrit 26 авг. '08 в 21:34
источник поделиться

Из Рик Стралл:

Вы можете связать?? оператора, чтобы вы могли выполнить нулевое сравнение.

string result = value1 ?? value2 ?? value3 ?? String.Empty;
528
ответ дан jfs 19 авг. '08 в 8:43
источник поделиться

Псевдонимы:

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

Это позволяет использовать ASimpleName вместо Dictionary<string, Dictionary<string, List<string>>>.

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

455
ответ дан BlackTigerX 16 сент. '08 в 19:53
источник поделиться

От CLR через С#:

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

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

438
ответ дан jfs 15 авг. '08 в 14:06
источник поделиться

Мой любимый трюк использует оператор null coalesce и круглые скобки для автоматического создания экземпляров для меня.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }
409
ответ дан Will 12 сент. '08 в 16:25
источник поделиться

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

Добавление пустого делегата к событиям в объявлении, подавляющее необходимость всегда проверять событие для 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");
    }
}

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

314
ответ дан andnil 13 авг. '08 в 0:57
источник поделиться

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

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
ответ дан Keith 12 авг. '08 в 21:23
источник поделиться

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

MyClass myObject = (MyClass) obj;

против

MyClass myObject = obj as MyClass;

Вторая возвращает null, если obj не является MyClass, а не бросает исключение класса.

286
ответ дан Mike Stone 12 авг. '08 в 19:42
источник поделиться

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

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
ответ дан lomaxx 13 авг. '08 в 10:39
источник поделиться

Ключевое слово default по умолчанию:

T t = default(T);

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

255
ответ дан Eric Minkes 13 авг. '08 в 13:20
источник поделиться

Атрибуты вообще, но больше всего DebuggerDisplay. Экономит ваши годы.

226
ответ дан Stu 12 авг. '08 в 19:59
источник поделиться

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

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

Если у вас

string s = @"cat
             dog
             fish"

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

cat
             dog
             fish
221
ответ дан lomaxx 13 авг. '08 в 5:07
источник поделиться

Я думаю, что одна из самых недооцененных и менее известных функций С# (.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);
    }
}

Это одна из главных причин того, что я сейчас люблю Лямбда и Деревни Expression.

220
ответ дан Jason Olson 10 сент. '08 в 0:52
источник поделиться

" yield" придет мне на ум. Некоторые из таких атрибутов, как [DefaultValue()], также относятся к моим фаворитам.

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

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

209
ответ дан Michael Stum 12 авг. '08 в 19:34
источник поделиться

Я обычно обнаруживаю, что большинство разработчиков С# не знают о типах "nullable". В принципе, примитивы, которые могут иметь нулевое значение.

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

Задайте значение nullable double, num1, null, затем установите регулярные двойные, 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
ответ дан Brad Barker 12 авг. '08 в 20:07
источник поделиться

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

__makeref

__reftype

__refvalue

__arglist

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

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

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

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

193
ответ дан Judah Himango 12 авг. '08 в 21:50
источник поделиться

Союзы (тип разделяемой памяти С++) в чистом, безопасном С#

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

[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;

185
ответ дан ZeroBugBounce 23 сент. '08 в 23:39
источник поделиться

Использование @для имен переменных, которые являются ключевыми словами.

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 
176
ответ дан Mark Cidade 18 авг. '08 в 4:45
источник поделиться

Если вы хотите выйти из своей программы, не вызывая никаких окончательных блоков или финализаторов, используйте FailFast:

Environment.FailFast()
168
ответ дан Jan Bannister 14 окт. '08 в 1:25
источник поделиться

Возвращение анонимных типов из метода и доступ к элементам без отражения.

// 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;
}
153
ответ дан denis phillips 17 авг. '08 в 4:01
источник поделиться

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

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

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

146
ответ дан Patrick 12 авг. '08 в 21:38
источник поделиться

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

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

Конечно, некоторая ясность приносится в жертву. Но это работает!

142
ответ дан Dmitri Nesteruk 26 окт. '08 в 22:04
источник поделиться

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

Правда, False, FileNotFound?

131
ответ дан Michael Stum 12 авг. '08 в 21:53
источник поделиться

Этот не скрыт настолько, насколько это неправильно.

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

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

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

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

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

117
ответ дан Brad Wilson 17 авг. '08 в 2:55
источник поделиться
Environment.NewLine

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

115
ответ дан nimish 01 сент. '08 в 3:03
источник поделиться

Если вы пытаетесь использовать фигурные скобки внутри выражения 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"
111
ответ дан Portman 19 авг. '08 в 1:29
источник поделиться
  • ? - коалесцирующий оператор
  • используя (statement/директива) - отличное ключевое слово, которое можно использовать не только для вызова Dispose
  • readonly - следует использовать больше
  • netmodules - слишком плохо там нет поддержки в Visual Studio
104
ответ дан kokos 12 авг. '08 в 19:35
источник поделиться

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

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

Если вы собираетесь использовать "is", зачем следить за ним с помощью безопасного броска, используя "как"? Если вы установили, что obj действительно MyClass, стандартное приложение для болота:

c = (MyClass)obj

... никогда не сработает.

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

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

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

103
ответ дан Dogmang 12 авг. '08 в 21:03
источник поделиться

Возможно, это не передовая техника, но я все время вижу, что сводит меня с ума:

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

можно конденсировать до:

x = (x==1) ? 2 : 3;
98
ответ дан JasonS 19 авг. '08 в 18:54
источник поделиться

Другие вопросы по меткам