This is a mirror of official site: http://jasper-net.blogspot.com/

Тонкие моменты C#

| Monday, February 14, 2011
Не секрет, что C# сегодня популярный и динамично развывающийся язык, в отличие от своего прямого конкурента — языка Java, который в плане функциональности переживает период застоя. Основное неоспоримое преимущество Java — настоящая кросплатформенность, а не унылая и ограниченная, как у C#.

C# — простой язык, благодаря простоте живёт и PHP. Но в то же время он весьма функциональный, и имеет статус «гибридного» языка, совмещая в себе различные парадигмы, встроенную поддержку как императивного стиля программирования, так и функционального.

Как и любой язык, шарп имеет свои тонкости, особенности, «подводные камни» и малоизвестные возможности. Что я имею ввиду? Читайте под катом…

Упаковка и распаковка — знают все, да не каждый

Ссылочные типы (object, dynamic, string, class, interface, delegate) хранятся в управляемой куче, типы значений (struct, enum; bool, byte, char, int, float, double) — в стеке приложения (кроме случая, когда тип значения является полем класса). Преобразование типа значений к ссылочному типу сопровождается неявной операцией упаковки (boxing) — помещение копии типа значений в класс-обёртку, экземпляр которого сохраняется в куче. Упаковочный тип генерируется CLR и реализует интерфейсы сохраняемого типа значения. Преобразование ссылочного типа к типу значений вызывает операцию распаковки (unboxing) — извлечение из упаковки копии типа значения и помещение её в стек.
using System;

class Program
{
 static void Main()
 {
   int val = 5;
   object obj = val;     // присваивание сопровождается упаковкой
   int valUnboxed = (int)obj; // приведение вызовет распаковку
 }
}

Соответствующий IL-код:

.locals init ([0] int32 val, [1] object obj, [2] int32 valUnboxed)
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: unbox.any [mscorlib]System.Int32
IL_0010: stloc.2
IL_0011: ret

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

class Program
{
 static void Main()
 {
   // 1. Преобразование типа значений в ссылку на реализуемый им интерфейс
   IComparable<int> iComp = 1;
   // 2. Преобразование типа enum в ссылку на System.Enum
   Enum format = UriFormat.Unescaped;
   // 3. Преобразование типа значений к типу dynamic
   dynamic d = 1;
 }
}

В msdn рекомендуется избегать типов значений в случаях, когда они должны быть упакованы много раз, например в не универсальных классах коллекций (ArrayList). Упаковки-преобразования типов значений можно избежать с помощью универсальных коллекций (System.Collections.Generic namespace). Также следует помнить, что dynamic на уровне IL-кода — это тот же object, только (не всегда) помеченный атрибутами.

Рекурсия в лямбдах — о зловредном замыкании

Обратимся к классической реализации рекурсивного вычисления факториала при помощи лямбда-выражений:

using System;
using System.Numerics;

class Program
{
 static void Main()
 {
   Func<int, BigInteger> fact = null;
   fact = x => x > 1 ? x * fact(x - 1) : 1;

Read more:  Habrahabr.ru

Posted via email from Jasper-net

0 comments: