View
507
Download
3
Category
Preview:
DESCRIPTION
31 мая – 1 июня в Киеве состоялась конференция HOTCODE 2013. Сергей Тепляков, эксперт Luxoft Training по .Net, С++ и архитектуре приложений, выступил с докладом «C# Deep Dive». Тезисы доклада: «Когда-то в далеком 2002-м году язык C# был прост, как 2 копейки. Но у любого «живого» языка есть одна особенность, приятная и неприятная одновременно — в язык начинают добавляться новые возможности, чтобы наши с вами типовые задачи решались проще и эффективнее. Но с каждой новой возможностью появляются и свои тонкости, незнание которых может лишить столь нужных в нашей жизни конечностей, причем иногда самым изощренным образом. А поскольку язык C# развивается очень динамично, то за время жизни на его просторах появилось много маленьких грабелек, которые мы с вами и научимся обходить ;)».
Citation preview
Deep DiveСергей Тепляков, Visual C# MVP
.NET Architect at LuxoftSergeyTeplyakov.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 25for n in 5 do printf "%d " n
Утинаятипизация
Если кто-то ходит, как утка, и крякает, как утка, то это и есть может быть утка индюшка с утиным адаптером...
« » Утинаятипизация в C#• foreach
• Требуется GetEnumerator, MoveNext и свойство Current• http://sergeyteplyakov.blogspot.com/2012/08/duck-typing-forea
ch.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); // 1var s = seq.Select(line => line.Length); // 2Console.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; // вызываем из потока 1a.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/
Recommended