SlideShare a Scribd company logo
1 of 29
Deep Dive
Сергей Тепляков, Visual C# MVP
.NET Architect at Luxoft
SergeyTeplyakov.blogspot.com
А насколько глубоко будем
нырять?
Настолько глубоко?
class X { public const int Value = 1000; }
static int Foo(Func<int?, byte> x, object y) { return 1; }
static int Foo(Func<X, byte> x, string y) { return 2; }
var a = Foo(X => (byte)X.Value, null);
unchecked
{
Console.WriteLine(a);
}
unchecked
{
var a = Foo(X => (byte)X.Value, null);
Console.WriteLine(a);
}
unchecked
{
var a = Foo(X => (byte)X.Value, (object)null);
Console.WriteLine(a);
} Увидим 1Увидим 2Снова 1!!!!
Нет! Нет! Нет!
• Подробнее об этом треше -
http://rsdn.ru/forum/dotnet/3272728.flat
• См. этюды nikov-а на rsdn.ru –
http://rsdn.ru/Forum/?fuid=55905
• Кури “The C# Programming Language” by Hejlsberg et al!
Что нужно для работы цикла
foreach?
• IEnumerable?
• IEnumerable of T?
• Что-то еще?
• Нужен метод GetEnumerator, возвращающий
объект с методом MoveNext и свойством
Current!
В F# пошли еще дальше…
• Поддержку цикла for можно добавить с помощью методов
расширения!
type Int32 with
// Получаем список квадратов чисел от 1 до текущего значения
member x.GetEnumerator() =
({1..x} |> Seq.map(fun x -> x*x)).GetEnumerator()
// Выводит 1 4 9 16 25
for n in 5 do printf "%d " n
Утиная типизация
Если кто-то ходит, как утка, и крякает, как
утка, то это и есть может быть утка индюшка
с утиным адаптером...
«Утиная типизация» в C#
• foreach
• Требуется GetEnumerator, MoveNext и свойство Current
• http://sergeyteplyakov.blogspot.com/2012/08/duck-typing-
foreach.html
• LINQ (Query Comprehension syntax)
• Требуются методы Select, Where, GroupBy etc.
• Collection initializer
• Требуется метод Add
• C# 5.0 Async Features
• Требуются GetAwaiter() и методы BeginAwait(Action) и
EndAwait(), GetResult() и свойства IsCompleted.
• System.Runtime.CompilerServices.ExtensionAttribute
• Методы расширения завязаны не на конкретный тип
атрибутов!
Блоки итераторов…
public static IEnumerable<string> ReadByLine(string path)
{
if (string.IsNullOrEmpty(path))
throw new ArgumentNullException("path");
using (var sr = new StreamReader(path))
{
string s;
while ((s = sr.ReadLine()) != null)
yield return s;
}
}
var seq = ReadByLine(null); // 1
var s = seq.Select(line => line.Length); // 2
Console.WriteLine(s.Max()); // 3
Все ли нормально с
кодом?
Этот же подход
используется и для
асинхронных методов!
Когда получим
исключение?
Код до первого yield
return вызовется при
первом вызове метода
MoveNext!
Какое исключение получим?
class Foo
{
public Foo() { throw new Exception("Ooops!!"); }
}
static T Create<T>() where T : new()
{
var instance = new T();
// Write to log some message
return instance;
}
var f = Create<Foo>();
Какое исключение
получим?
Почему?
• Используется reflection (Activator.CreateInstance).
• Все обобщения должны содержать одну реализацию!
• Вызов метода через Reflection всегда «оборачивает»
исходное исключение в TargetInvocationException
• «Все нетривиальные абстракции текут»
Джоэл Спольски
Есть ли проблема?
using (var file = new FileStream("D:1.txt", FileMode.CreateNew)
{
Position = RestoreLastPosition()
})
{}
Как устроен Object Initializer?
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
// ...
var person = new Person {Name = "Jonh", Age = 42};
var tmp = new Person();
tmp.Name = "Jonh";
tmp.Age = 42;
var person = tmp;
Как устроен using?
using (var file = new FileStream("D:1.txt", FileMode.CreateNew))
{}
var file = new FileStream("d:1.txt", FileMode.CreateNew);
try
{}
finally
{
if (file != null)
((IDisposable)file).Dispose();
}
Складываем 2 и 2…
var tmpFile = new FileStream("d:1.txt", FileMode.CreateNew);
// Упс! Если мы здесь упадем, то Dispose вызван не будет!
tmpFile.Position = RestoreLastPosition();
var file = tmpFile;
try
{ }
finally
{
if (file != null)
((IDisposable)file).Dispose();
}
Потокобезопасная подписка
на событие?
class A
{
public event EventHandler E;
public void Subscribe(EventHandler e)
{
E = E + e;
}
}
var a = new A();
EventHandler handler = (o, e) => Console.WriteLine("Handler");
a.E += handler; // вызываем из потока 1
a.Subscribe(handler); // вызываем из потока 2
Подробнее об этом –
Chris Burrow "Events get a little overhaul in C# 4, Part II"
Является ли такая
подписка «изнутри»
потокобезопасной?
Такой вариант не
безопасен!
Как устроены события?
class AImpl
{
private EventHandler __E;
public event EventHandler E
{
add
{
lock (this) { __E += value; }
}
remove
{
lock (this) { __E += value; }
}
}
public void Subscribe(EventHandler e)
{
__E = (EventHandler)Delegate.Combine(__E, e);
}
}
В C# 4.0 используется
lock-free подход.
А вместо «сырого»
Combine для E+= value
вызывается
экземплярный Add!
В C# 4.0…
• События C# 4.0 полностью потокобезопасны
• Подписка на событие «изнутри» класса приводит к вызову
Add текущего объекта
// В C# 4.0 решение полностью потокобезопасно!
class A
{
public event EventHandler E;
public void Subscribe(EventHandler e)
{
E += e;
}
public void RaiseE()
{
var handler = E;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
Делегаты…
static void SubscribeTo(EventHandler e)
{
e += (s, ea) => Console.WriteLine("Custom handler");
}
EventHandler handler = null;
SubscribeTo(handler);
handler(null, EventArgs.Empty);
Что произойдет при
вызове?
Делегаты – неизменяемы…
• Ведь этот трюк все же знают!
class A
{
public event EventHandler E;
public void RaiseE()
{
var handler = E;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
Не на 100% thread-safe в
теории, но thread-safe на
практике!
Виртуальные события
class Base
{
public virtual event EventHandler SomeEvent;
public void RaiseSomeEvent()
{
var handler = SomeEvent;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
class Derived : Base
{
public override event EventHandler SomeEvent;
}
Base b = new Derived();
b.SomeEvent += (s, e) =>
Console.WriteLine("Handler");
b.RaiseSomeEvent();
struct S1
{
private readonly int X;
public int GetX() { return X; }
}
struct S2
{
public int X;
}
[StructLayout(LayoutKind.Explicit)]
struct S3
{
[FieldOffset(0)]
public S1 S1;
[FieldOffset(0)]
public S2 S2;
}
var s3 = new S3();
s3.S2.X = 42;
Console.WriteLine(s3.S1.GetX());
Readonly. Правда?
X изменить нельзя!
Правда ведь?
Да это же union из С/С++!!!
Получим 42!!
class ArrayHacker
{
public int Length;
}
[StructLayout(LayoutKind.Explicit)]
class ArrayHack
{
[FieldOffset(0)]
public ArrayHacker Hacker;
[FieldOffset(0)]
public int[] Array = new int[2];
}
void Main()
{
var hack = new ArrayHack();
Console.WriteLine(hack.Array.Length); // 2
hack.Hacker.Length = 42;
Console.WriteLine(hack.Array.Length); // 42!!
hack.Array.Dump(); // Получаем "мусор"
}
Изменяем размер массива!
Первые 4 байта массива – это
его размер!
А стоит ли их вообще
использовать?
• А как же! Ногу, ведь, чем-то нужно отпиливать!
• Есть приложения, а есть библиотеки – это разные миры.
• Понимание внутреннего устройства сведет проблемы к
минимуму!
Нееееттт!!!!1111
Вопросы?
Чего еще почитать?
• Programming Stuff
• C# Tips and Tricks
• Chris Burrows’ Blog
• Eric Lippert’s Blog
• Joe Duffy’s Weblog
• B# .NET BLOG
More C# Deep Dive on
Programming Stuff
• this == null?
• Замыкания в языке C#
• Перегрузка и наследование
• Структуры и конструкторы по умолчанию
• О вреде изменяемых значимых типов.
• Часть 1
• Часть 2
• MVP Summit. День 0. Кэширование делегатов
• MVP Summit. День 1. Об эффективности
Спасибо за внимание
• Сергей Тепляков, Visual C# MVP
• .NET Architect at Luxoft
• Sergey.Teplyakov@gmail.com
• http://sergeyteplyakov.blogspot.com/

More Related Content

What's hot

Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о BoostSergey Platonov
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Yauheni Akhotnikau
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsPlatonov Sergey
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Sergey Platonov
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Sergey Platonov
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеPython Meetup
 
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Platonov Sergey
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийAndrey Akinshin
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковSergey Platonov
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castRoman Orlov
 
Haskell
HaskellHaskell
HaskellDevDay
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3Eugeniy Tyumentcev
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Victor_Cr
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2Eugeniy Tyumentcev
 

What's hot (20)

Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о Boost
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free maps
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгирование
 
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложений
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
 
Zagursky
ZagurskyZagursky
Zagursky
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
Haskell
HaskellHaskell
Haskell
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
Clojure #2 (2014)
Clojure #2 (2014)Clojure #2 (2014)
Clojure #2 (2014)
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизация
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)
 
Clojure #1
Clojure #1Clojure #1
Clojure #1
 
Java 8 puzzlers
Java 8 puzzlersJava 8 puzzlers
Java 8 puzzlers
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2
 

Similar to C sharp deep dive

C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному кодуVasiliy Deynega
 
NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript Dmytro Mindra
 
Ciklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScriptCiklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScriptDmytro Mindra
 
Statis code analysis
Statis code analysisStatis code analysis
Statis code analysischashnikov
 
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Sigma Software
 
Язык программирования C#
Язык программирования C#Язык программирования C#
Язык программирования C#Dmitri Soshnikov
 
Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)Dmitry Stropalov
 
Convert this: peculiarities of cross-platform mobile game development at Vizor
Convert this: peculiarities of cross-platform mobile game development at VizorConvert this: peculiarities of cross-platform mobile game development at Vizor
Convert this: peculiarities of cross-platform mobile game development at VizorDevGAMM Conference
 
Web осень 2012 лекция 9
Web осень 2012 лекция 9Web осень 2012 лекция 9
Web осень 2012 лекция 9Technopark
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокAndrey Karpov
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Stfalcon Meetups
 
DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6Dmitry Soshnikov
 
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...OdessaFrontend
 

Similar to C sharp deep dive (20)

Асинхронный JavaScript
Асинхронный JavaScriptАсинхронный JavaScript
Асинхронный JavaScript
 
Reactive extensions
Reactive extensionsReactive extensions
Reactive extensions
 
C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному коду
 
NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript
 
Ciklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScriptCiklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScript
 
Bytecode
BytecodeBytecode
Bytecode
 
Statis code analysis
Statis code analysisStatis code analysis
Statis code analysis
 
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
 
Thread
ThreadThread
Thread
 
JavaScript Intro
JavaScript IntroJavaScript Intro
JavaScript Intro
 
Язык программирования C#
Язык программирования C#Язык программирования C#
Язык программирования C#
 
Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)
 
Convert this: peculiarities of cross-platform mobile game development at Vizor
Convert this: peculiarities of cross-platform mobile game development at VizorConvert this: peculiarities of cross-platform mobile game development at Vizor
Convert this: peculiarities of cross-platform mobile game development at Vizor
 
Scala on android
Scala on androidScala on android
Scala on android
 
Web осень 2012 лекция 9
Web осень 2012 лекция 9Web осень 2012 лекция 9
Web осень 2012 лекция 9
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8
 
DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6
 
Scala for android
Scala for androidScala for android
Scala for android
 
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
 

More from Sergey Teplyakov

Void safety on Kiev ALT.NET
Void safety on Kiev ALT.NETVoid safety on Kiev ALT.NET
Void safety on Kiev ALT.NETSergey Teplyakov
 
Тонкости асинхронного программирования
Тонкости асинхронного программированияТонкости асинхронного программирования
Тонкости асинхронного программированияSergey Teplyakov
 
MS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilityMS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilitySergey Teplyakov
 

More from Sergey Teplyakov (6)

Void safety on Kiev ALT.NET
Void safety on Kiev ALT.NETVoid safety on Kiev ALT.NET
Void safety on Kiev ALT.NET
 
Тонкости асинхронного программирования
Тонкости асинхронного программированияТонкости асинхронного программирования
Тонкости асинхронного программирования
 
MS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilityMS SWIT 2013 Design for Testability
MS SWIT 2013 Design for Testability
 
Design by Contract basics
Design by Contract basicsDesign by Contract basics
Design by Contract basics
 
Visual studio toolbox
Visual studio toolboxVisual studio toolbox
Visual studio toolbox
 
Luxoft async.net
Luxoft async.netLuxoft async.net
Luxoft async.net
 

C sharp deep dive

  • 1. Deep Dive Сергей Тепляков, Visual C# MVP .NET Architect at Luxoft SergeyTeplyakov.blogspot.com
  • 2. А насколько глубоко будем нырять?
  • 3. Настолько глубоко? class X { public const int Value = 1000; } static int Foo(Func<int?, byte> x, object y) { return 1; } static int Foo(Func<X, byte> x, string y) { return 2; } var a = Foo(X => (byte)X.Value, null); unchecked { Console.WriteLine(a); } unchecked { var a = Foo(X => (byte)X.Value, null); Console.WriteLine(a); } unchecked { var a = Foo(X => (byte)X.Value, (object)null); Console.WriteLine(a); } Увидим 1Увидим 2Снова 1!!!!
  • 4. Нет! Нет! Нет! • Подробнее об этом треше - http://rsdn.ru/forum/dotnet/3272728.flat • См. этюды nikov-а на rsdn.ru – http://rsdn.ru/Forum/?fuid=55905 • Кури “The C# Programming Language” by Hejlsberg et al!
  • 5. Что нужно для работы цикла foreach? • IEnumerable? • IEnumerable of T? • Что-то еще? • Нужен метод GetEnumerator, возвращающий объект с методом MoveNext и свойством Current!
  • 6. В F# пошли еще дальше… • Поддержку цикла for можно добавить с помощью методов расширения! type Int32 with // Получаем список квадратов чисел от 1 до текущего значения member x.GetEnumerator() = ({1..x} |> Seq.map(fun x -> x*x)).GetEnumerator() // Выводит 1 4 9 16 25 for n in 5 do printf "%d " n
  • 7. Утиная типизация Если кто-то ходит, как утка, и крякает, как утка, то это и есть может быть утка индюшка с утиным адаптером...
  • 8. «Утиная типизация» в C# • foreach • Требуется GetEnumerator, MoveNext и свойство Current • http://sergeyteplyakov.blogspot.com/2012/08/duck-typing- foreach.html • LINQ (Query Comprehension syntax) • Требуются методы Select, Where, GroupBy etc. • Collection initializer • Требуется метод Add • C# 5.0 Async Features • Требуются GetAwaiter() и методы BeginAwait(Action) и EndAwait(), GetResult() и свойства IsCompleted. • System.Runtime.CompilerServices.ExtensionAttribute • Методы расширения завязаны не на конкретный тип атрибутов!
  • 9. Блоки итераторов… public static IEnumerable<string> ReadByLine(string path) { if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path"); using (var sr = new StreamReader(path)) { string s; while ((s = sr.ReadLine()) != null) yield return s; } } var seq = ReadByLine(null); // 1 var s = seq.Select(line => line.Length); // 2 Console.WriteLine(s.Max()); // 3 Все ли нормально с кодом? Этот же подход используется и для асинхронных методов! Когда получим исключение? Код до первого yield return вызовется при первом вызове метода MoveNext!
  • 10. Какое исключение получим? class Foo { public Foo() { throw new Exception("Ooops!!"); } } static T Create<T>() where T : new() { var instance = new T(); // Write to log some message return instance; } var f = Create<Foo>(); Какое исключение получим?
  • 11. Почему? • Используется reflection (Activator.CreateInstance). • Все обобщения должны содержать одну реализацию! • Вызов метода через Reflection всегда «оборачивает» исходное исключение в TargetInvocationException • «Все нетривиальные абстракции текут» Джоэл Спольски
  • 12. Есть ли проблема? using (var file = new FileStream("D:1.txt", FileMode.CreateNew) { Position = RestoreLastPosition() }) {}
  • 13. Как устроен Object Initializer? class Person { public string Name { get; set; } public int Age { get; set; } } // ... var person = new Person {Name = "Jonh", Age = 42}; var tmp = new Person(); tmp.Name = "Jonh"; tmp.Age = 42; var person = tmp;
  • 14. Как устроен using? using (var file = new FileStream("D:1.txt", FileMode.CreateNew)) {} var file = new FileStream("d:1.txt", FileMode.CreateNew); try {} finally { if (file != null) ((IDisposable)file).Dispose(); }
  • 15. Складываем 2 и 2… var tmpFile = new FileStream("d:1.txt", FileMode.CreateNew); // Упс! Если мы здесь упадем, то Dispose вызван не будет! tmpFile.Position = RestoreLastPosition(); var file = tmpFile; try { } finally { if (file != null) ((IDisposable)file).Dispose(); }
  • 16. Потокобезопасная подписка на событие? class A { public event EventHandler E; public void Subscribe(EventHandler e) { E = E + e; } } var a = new A(); EventHandler handler = (o, e) => Console.WriteLine("Handler"); a.E += handler; // вызываем из потока 1 a.Subscribe(handler); // вызываем из потока 2 Подробнее об этом – Chris Burrow "Events get a little overhaul in C# 4, Part II" Является ли такая подписка «изнутри» потокобезопасной? Такой вариант не безопасен!
  • 17. Как устроены события? class AImpl { private EventHandler __E; public event EventHandler E { add { lock (this) { __E += value; } } remove { lock (this) { __E += value; } } } public void Subscribe(EventHandler e) { __E = (EventHandler)Delegate.Combine(__E, e); } } В C# 4.0 используется lock-free подход. А вместо «сырого» Combine для E+= value вызывается экземплярный Add!
  • 18. В C# 4.0… • События C# 4.0 полностью потокобезопасны • Подписка на событие «изнутри» класса приводит к вызову Add текущего объекта // В C# 4.0 решение полностью потокобезопасно! class A { public event EventHandler E; public void Subscribe(EventHandler e) { E += e; } public void RaiseE() { var handler = E; if (handler != null) handler(this, EventArgs.Empty); } }
  • 19. Делегаты… static void SubscribeTo(EventHandler e) { e += (s, ea) => Console.WriteLine("Custom handler"); } EventHandler handler = null; SubscribeTo(handler); handler(null, EventArgs.Empty); Что произойдет при вызове?
  • 20. Делегаты – неизменяемы… • Ведь этот трюк все же знают! class A { public event EventHandler E; public void RaiseE() { var handler = E; if (handler != null) handler(this, EventArgs.Empty); } } Не на 100% thread-safe в теории, но thread-safe на практике!
  • 21. Виртуальные события class Base { public virtual event EventHandler SomeEvent; public void RaiseSomeEvent() { var handler = SomeEvent; if (handler != null) handler(this, EventArgs.Empty); } } class Derived : Base { public override event EventHandler SomeEvent; } Base b = new Derived(); b.SomeEvent += (s, e) => Console.WriteLine("Handler"); b.RaiseSomeEvent();
  • 22. struct S1 { private readonly int X; public int GetX() { return X; } } struct S2 { public int X; } [StructLayout(LayoutKind.Explicit)] struct S3 { [FieldOffset(0)] public S1 S1; [FieldOffset(0)] public S2 S2; } var s3 = new S3(); s3.S2.X = 42; Console.WriteLine(s3.S1.GetX()); Readonly. Правда? X изменить нельзя! Правда ведь? Да это же union из С/С++!!! Получим 42!!
  • 23. class ArrayHacker { public int Length; } [StructLayout(LayoutKind.Explicit)] class ArrayHack { [FieldOffset(0)] public ArrayHacker Hacker; [FieldOffset(0)] public int[] Array = new int[2]; } void Main() { var hack = new ArrayHack(); Console.WriteLine(hack.Array.Length); // 2 hack.Hacker.Length = 42; Console.WriteLine(hack.Array.Length); // 42!! hack.Array.Dump(); // Получаем "мусор" } Изменяем размер массива! Первые 4 байта массива – это его размер!
  • 24. А стоит ли их вообще использовать? • А как же! Ногу, ведь, чем-то нужно отпиливать! • Есть приложения, а есть библиотеки – это разные миры. • Понимание внутреннего устройства сведет проблемы к минимуму!
  • 27. Чего еще почитать? • Programming Stuff • C# Tips and Tricks • Chris Burrows’ Blog • Eric Lippert’s Blog • Joe Duffy’s Weblog • B# .NET BLOG
  • 28. More C# Deep Dive on Programming Stuff • this == null? • Замыкания в языке C# • Перегрузка и наследование • Структуры и конструкторы по умолчанию • О вреде изменяемых значимых типов. • Часть 1 • Часть 2 • MVP Summit. День 0. Кэширование делегатов • MVP Summit. День 1. Об эффективности
  • 29. Спасибо за внимание • Сергей Тепляков, Visual C# MVP • .NET Architect at Luxoft • Sergey.Teplyakov@gmail.com • http://sergeyteplyakov.blogspot.com/

Editor's Notes

  1. Тут приходит в голову очень пошлая фотка)
  2. // TODO: Сделать пометки, почему ведет себя код именно так! Сказать, что readonly – доступ к ней – это не обращение к переменной, а получение значения! Добавить b.M.Y++, что это тоже не компилится, поскольку b.M - rvalue