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

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

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

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

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

string path = dir + "\\" + fileName;
752
ответ дан 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
ответ дан 26 авг. '08 в 21:34
источник

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

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

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

Псевдонимы:

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

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

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

455
ответ дан 16 сент. '08 в 19:53
источник

От CLR через С#:

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

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

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

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

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }
409
ответ дан 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
ответ дан 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
ответ дан 12 авг. '08 в 21:23
источник

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

MyClass myObject = (MyClass) obj;

против

MyClass myObject = obj as MyClass;

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

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

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

T t = default(T);

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

255
ответ дан 13 авг. '08 в 13:20
источник

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

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

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

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

Если у вас

string s = @"cat
             dog
             fish"

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

cat
             dog
             fish
221
ответ дан 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
ответ дан 10 сент. '08 в 0:52
источник

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

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

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

209
ответ дан 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
ответ дан 12 авг. '08 в 20:07
источник

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

__makeref

__reftype

__refvalue

__arglist

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

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

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

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

193
ответ дан 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
ответ дан 23 сент. '08 в 23:39
источник

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

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

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

Environment.FailFast()
168
ответ дан 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
ответ дан 17 авг. '08 в 4:01
источник

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

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

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

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

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

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

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

142
ответ дан 26 окт. '08 в 22:04
источник

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

Правда, False, FileNotFound?

131
ответ дан 12 авг. '08 в 21:53
источник

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

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

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

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

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

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

117
ответ дан 17 авг. '08 в 2:55
источник
Environment.NewLine

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

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

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

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

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

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

Другие вопросы по меткам или Задайте вопрос