Туда и обратно. Тёмная сторона сериализации презентация

Содержание

Слайд 3

О себе

Зарабатываю на жизнь программированием с 2005 года
Программировал еще на .net framework 1.0
Помню

С# без Generics
Складывал объекты ArrayList
Использовал BinaryFormatter ¯\_(ツ)_/¯

Слайд 4

“ЗОЧЕМ?
Есть же <выберите свой сериализатор>?”

Слайд 5

Варианты

Protocol Buffers
Json
Newtonsoft.Json
System.Text.Json
etc
BinaryFormatter
XmlFormatter
другие

Слайд 6

Причины

Слайд 7

Причины

Экзотические форматы

Слайд 8

Причины

Экзотические форматы
Лучшая производительность

Слайд 9

Причины

Экзотические форматы
Лучшая производительность
Другие сценарии использования Reflection:
Data-binding
Object-object mapping
Логирование: Destructing

Слайд 10

О докладе

Доступ к данным: Reflection и альтернативы
Производительность различных способов доступа
Участие доступа к данным

в процессе сериализации

Слайд 11

Прямой доступ vs. Reflection

Слайд 13

System.Reflection

System.Object
GetType()

Слайд 14

System.Reflection

System.Object
GetType()
System.Type
GetProperties(...)

Слайд 15

System.Reflection

System.Object
GetType()
System.Type
GetProperties(...)
System.Reflection.PropertyInfo
Name
PropertyType
GetValue/SetValue

Слайд 16

“Все знают, что
Reflection это Медленно!!!”

Слайд 17

Type System Overview

Слайд 18

Насколько Reflection это медленно?

Слайд 19

Цифры

Слайд 28

Ba Dum Tss!

Слайд 29

Ba Dum Tss!

Слайд 30

“Давай закэшируем PropertyInfo!”

Слайд 32

Cached PropertyInfo

Слайд 33

Cached PropertyInfo

Слайд 35

“Неужели нет другого способа?!”

Слайд 37

FastMember

Слайд 38

FastMember

Слайд 39

FastMember

Слайд 42

“Безнадёга?”

Слайд 43

Delegate.CreateDelegate

Слайд 44

Delegate

Открытые / Закрытые

Слайд 45

Delegate: открытые/закрытые

Слайд 46

Delegate: открытые/закрытые

Слайд 47

Delegate: открытые/закрытые

Слайд 48

Delegate.CreateDelegate

Слайд 49

Delegate.CreateDelegate

Слайд 50

PropertyInfo ➝ MethodInfo

Слайд 51

PropertyInfo ➝ MethodInfo

GetGetMethod() / GetSetMethod()

Слайд 52

Delegate.CreateDelegate

Слайд 53

Delegate.CreateDelegate

Слайд 54

Delegate.CreateDelegate

Слайд 55

Delegate.CreateDelegate

Слайд 56

Delegate.CreateDelegate

Слайд 57

Delegate.CreateDelegate

Слайд 60

“А может генерировать код в runtime?”

Слайд 61

Генерация кода в runtime

Слайд 62

Генерация кода в runtime

IL Emit

Слайд 63

Генерация кода в runtime

IL Emit
Compiled Expression Trees

Слайд 65

Intermediate Language

Слайд 67

public string GetViaProperty() => _test.StringProperty;

Слайд 68

.method private hidebysig
static string GetViaProperty( class Test target)
cil managed
{
.maxstack 1

ldarg.0
callvirt instance string Test::get_StringProperty()
ret
}

public string GetViaProperty() => _test.StringProperty;

Слайд 69

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod(true);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 70

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod(true);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 71

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod(true);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 72

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod(true);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 73

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod(true);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 74

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 75

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 76

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 77

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 78

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 79

public static Func GenerateGetter(PropertyInfo property)
{
var method = new DynamicMethod(property.Name + "GetterTyped",

typeof(TParam),
new[] { typeof(TTarget) },
Module, true);
var gen = method.GetILGenerator();
var getMethod = property.GetGetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, getMethod);
gen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func));
}

Слайд 80

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 81

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 82

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 83

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 84

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 85

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 86

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 87

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 88

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 89

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 90

static Action GenerateSetter(PropertyInfo propertyInfo)
{
var method = new DynamicMethod(propertyInfo.Name + "SetterTyped", null,

new[] { typeof(TTarget), typeof(TParam) }, Module, true);
var gen = method.GetILGenerator();
var setMethod = propertyInfo.GetSetMethod();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, setMethod);
gen.Emit(OpCodes.Ret);
return (Action)method.CreateDelegate(typeof(Action));
}

Слайд 91

Intermediate Language

Слайд 92

Intermediate Language

Слайд 93

Intermediate Language

Слайд 94

Compiled Expression Trees

Слайд 95

Expression Trees

Слайд 96

Expression Trees

Lambda Expressions

Слайд 97

Expression Trees

Lambda Expressions
API

Слайд 98

Expression Trees: Lambda

Слайд 99

Expression Trees: Lambda

Слайд 100

Expression Trees: API

Слайд 115

Expression Trees: API

Слайд 116

Expression Trees: API

Слайд 117

Expression Trees: API

Слайд 118

Expression Trees: API

Слайд 121

Ни рефлексией единой

Reflection - медленно

Слайд 122

Ни рефлексией единой

Reflection - медленно
Альтернативы “из коробки” - быстрее

Слайд 123

Ни рефлексией единой

Reflection - медленно
Альтернативы “из коробки” - быстрее
Требуют усилий

Слайд 124

“Погоди! Но ...”

Слайд 125

“Делегаты специфицированы конкретными типами целевого объекта и его свойства!”

Слайд 129

PropertyInfo.GetValue

Слайд 130

Delegate.CreateDelegate

Слайд 131

Delegate.CreateDelegate

Слайд 132

System.ArgumentException

Cannot bind to the target method because its signature is not compatible with

that of the delegate type.
at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, MethodInfo method)
at Program.Main() in Program.cs

Слайд 133

“Эх! А счастье было так близко...”

Слайд 134

Delegate (object, object)

Слайд 135

Delegate (object, object)

Слайд 136

Delegate (object, object)

Слайд 137

Delegate (object, object)

Слайд 138

Delegate (object, object)

Слайд 139

Delegate (object, object)

Слайд 140

Delegate (object, object)

Слайд 141

Delegate (object, object)

Слайд 142

Delegate (object, object)

Слайд 144

Delegate (object, object)

Слайд 145

Delegate (object, object)

Слайд 146

ILGen (object, object)

Слайд 147

ILGen (object, object)

Слайд 148

ILGen (object, object)

Слайд 149

ILGen (object, object)

Слайд 150

ILGen (object, object)

Слайд 151

ILGen (object, object)

Слайд 152

Expression Trees (object, object)

Слайд 153

Expression Trees (object, object)

Слайд 154

Expression Trees (object, object)

Слайд 155

Expression Trees (object, object)

Слайд 156

Expression Trees (object, object)

Слайд 159

Ни рефлексией единой

Reflection - медленно

Слайд 160

Ни рефлексией единой

Reflection - медленно
Нетипизированный доступ

Слайд 161

Ни рефлексией единой

Reflection - медленно
Нетипизированный доступ
Альтернативы “из коробки” - быстрее

Слайд 162

Ни рефлексией единой

Reflection - медленно
Нетипизированный доступ
Альтернативы “из коробки” - быстрее
Типизированный доступ

Слайд 163

Ни рефлексией единой

Reflection - медленно
Нетипизированный доступ
Альтернативы “из коробки” - быстрее
Типизированный доступ
Reflection-like

Слайд 164

Ни рефлексией единой

Reflection - медленно
Нетипизированный доступ
Альтернативы “из коробки” - быстрее
Типизированный доступ
Reflection-like
Требуют усилий

Слайд 165

“А что если ValueType? Boxing же!”

Слайд 172

Ни рефлексией единой: Value Type

Слайд 173

Ни рефлексией единой: Value Type

Reflection: boxing

Слайд 174

Ни рефлексией единой: Value Type

Reflection: boxing
Альтернатива
Reflection-like: boxing

Слайд 175

Ни рефлексией единой: Value Type

Reflection: boxing
Альтернатива
Reflection-like: boxing
Типизированный доступ: no boxing

Слайд 176

Приватные данные

Слайд 181

Доступ к данным

Слайд 182

Доступ к данным

Reflection

Слайд 183

Доступ к данным

Reflection:
Медленно

Слайд 184

Доступ к данным

Reflection:
Медленно
Boxing

Слайд 185

Доступ к данным

Reflection:
Медленно
Boxing
Альтернативы

Слайд 186

Доступ к данным

Reflection:
Медленно
Boxing
Альтернативы:
Сильно быстрее Reflection

Слайд 187

Доступ к данным

Reflection:
Медленно
Boxing
Альтернативы:
Сильно быстрее Reflection
Boxing

Слайд 188

Доступ к данным

Reflection:
Медленно
Boxing
Альтернативы:
Сильно быстрее Reflection
Boxing / No Boxing

Слайд 189

Доступ к данным

Reflection:
Медленно
Boxing
Альтернативы:
Сильно быстрее Reflection
Boxing / No Boxing
Можно и приватные данные (поля,

свойства)

Слайд 190

Доступ к данным

Reflection:
Медленно
Boxing
Альтернативы:
Сильно быстрее Reflection
Boxing / No Boxing
Можно и приватные данные (поля,

свойства)
Прямое чтение/запись не обойти

Слайд 192

Сценарий использования

Слайд 193

Сериализация

Слайд 194

Сериализация

Слайд 195

Сериализация

Слайд 196

Сериализация

Слайд 197

Сериализация

Слайд 198

Сериализация

Слайд 200

Сгенерированный сериализатор

Слайд 201

Сгенерированный сериализатор

Слайд 202

Сериализация

Слайд 207

ValueType. Reflection-like

Слайд 208

ValueType. Generated

Слайд 215

Ни рефлексией единой

BinaryFormatter
Newtonsoft.Json
System.Text.Json
Google.Protobuf
AutoMapper

Слайд 216

Ни рефлексией единой

BinaryFormatter: Reflection
Newtonsoft.Json
System.Text.Json
Google.Protobuf
AutoMapper

Слайд 217

Ни рефлексией единой

BinaryFormatter: Reflection ¯\_(ツ)_/¯
Newtonsoft.Json
System.Text.Json
Google.Protobuf
AutoMapper

Слайд 218

Ни рефлексией единой

BinaryFormatter: Reflection
Newtonsoft.Json: IL Emit
System.Text.Json
Google.Protobuf
AutoMapper

Слайд 219

Ни рефлексией единой

BinaryFormatter: Reflection
Newtonsoft.Json: IL Emit
System.Text.Json: IL Emit
Google.Protobuf
AutoMapper

Слайд 220

Ни рефлексией единой

BinaryFormatter: Reflection
Newtonsoft.Json: IL Emit
System.Text.Json: IL Emit
Google.Protobuf: Property
AutoMapper

Слайд 221

Ни рефлексией единой

BinaryFormatter: Reflection
Newtonsoft.Json: IL Emit
System.Text.Json: IL Emit
Google.Protobuf: Property (Генерация C# - кода)
AutoMapper

Слайд 222

Ни рефлексией единой

BinaryFormatter: Reflection
Newtonsoft.Json: IL Emit
System.Text.Json: IL Emit
Google.Protobuf: Property (Генерация C# - кода)
AutoMapper:

Expression Trees

Слайд 223

Осталось за скобками

Безопасность
Инстанцирование объектов (new, CreateInstance)
Парсинг данных
Схема и версионирование данных
Генерация C# - кода


Слайд 224

Ни рефлексией единой

Reflection - медленно
Есть достойные альтернативы:
CreateDelegate / IL Emit / Expression Trees
Доступ

к данным еще не всё
Runtime генерация кода для “сложных” случаев
Имя файла: Туда-и-обратно.-Тёмная-сторона-сериализации.pptx
Количество просмотров: 76
Количество скачиваний: 0