Вы находитесь на странице: 1из 320

32.973.

2-018-02
004.42
34

34

.NET. .: , 2015. 320 .: .

ISBN 978-5-496-01649-0
,
. ,
, .
, ,
, ,
.NET-.
.NET,
.NET Framework. , SOLID, .
,
C#
.NET.

12+ ( 29 2010 . 436-.)



32.973.2-018-02
004.42

.
.
, , , . , ,

, .

ISBN 978-5-496-01649-0

, 2015


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

I.
1. (Strategy) . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

2. (Template Method) . . . . . . .

37

3. (Mediator) . . . . . . . . . . . . . . . . . . . . . . . . .

57

4. (Iterator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

5. (Observer) . . . . . . . . . . . . . . . . . . . . . .

83

6. (Visitor) . . . . . . . . . . . . . . . . . . . . . . . . . .

100

7. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

112

II.
8. (Singleton) . . . . . . . . . . . . . . . . . . . . . . . . .

122

9. (Abstract Factory) . . . .

137

10. (FactoryMethod) . . . . . . .

145

11. (Builder) . . . . . . . . . . . . . . . . . . . . . . . . .

160

III.
12. (Adapter) . . . . . . . . . . . . . . . . . . . . . . . . . .

188

13. (Facade) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

197

14. (Decorator) . . . . . . . . . . . . . . . . . . . . . .

201

15. (Composite) . . . . . . . . . . . . . . . . 214


16. (Proxy) . . . . . . . . . . . . . . . . . . . . . . . .

221

IV.
17. . . . . . . . . . . . . . . . . .

231

18. / . . . . . . . . . . . . . . . . . . . . . . . . . . . .

243

19. . . . . . . . . . . . . . . . . . . . . . . . . .

260

20. . . . . . . . . . . . . . . . . . . .

275

21. . . . . . . . . . . . . . . . . . . . .

284

22. . . . . . . . .

305

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

311

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

313


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

GoF- .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

I.
1. (Strategy) . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

2. (Template Method) . . . . . . .

37

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
. . . . . . . . . . . . . . . . . . . . . 39
. . . . . . . . . . . . . . . . . . . . . 42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

3. (Mediator) . . . . . . . . . . . . . . . . . . . . . . . . .

57

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
? ! . . . . . . . . . . . . . . . . . . . . . 64
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

4. (Iterator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

C#/.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
foreach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Push-based- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

5. (Observer) . . . . . . . . . . . . . . . . . . . . . .

83

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
IObserver/IObservable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
. . . . . . . . . . . . . . . . . . . . . . . . . . 93
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
. . . . . . . . . . . . . . . . . . . . . . . 94
. . . . . . . . . . . . . . . . . . . . . . . . 95
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

6. (Visitor) . . . . . . . . . . . . . . . . . . . . . . . . . .

100

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
vs. . . . . . . . . . . . . . . . . . . . . . . . . . 109
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

7. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

112

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

II.
8. (Singleton) . . . . . . . . . . . . . . . . . . . . . . . . .

122

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Lazy of T . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
. . . . . . . . . . . . . . 126
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Singleton vs. Ambient Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Singleton vs. Static Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

9. (Abstract Factory) . . . .

137

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

10

. . . . . . . . . . . . . . . . . . . . . . . . . . . 143
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

10. (FactoryMethod) . . . . . . .

145

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
. . . . . . . . . . . . . . . . . . . . . 149
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Func . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
. . . . . . . . . . . . . . . . . . . . . 157
. . . . . . . . . . . . . . . . . . . . 157
. . . . . . . . . . . . . . . . . . . . . . 158
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

11. (Builder) . . . . . . . . . . . . . . . . . . . . . . . . .

160

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

III.
12. (Adapter) . . . . . . . . . . . . . . . . . . . . . . . . . .

188

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196

13. (Facade) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

197

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

14. (Decorator) . . . . . . . . . . . . . . . . . . . . . .

201

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

11

12

15. (Composite) . . . . . . . . . . . . . . . . 214


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

16. (Proxy) . . . . . . . . . . . . . . . . . . . . . . . .

221

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Lazy<T> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

IV.
17. . . . . . . . . . . . . . . . . .

231

SRP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
. . . . . . . . . . . . . . . . . . . . . . . . . . . 233
SRP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242

18. / . . . . . . . . . . . . . . . . . . . . . . . . . . . .

243

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
/ . . . . . . . . . . . . . . . . . . 247
/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

: - . . . . . . 254
/ . . . . . . . . . . . . . . . . . . 258
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258

19. . . . . . . . . . . . . . . . . . . . . . . . . .

260

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
: . . . . . . . . . . . . . . . 263
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
LSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

20. . . . . . . . . . . . . . . . . . . .

275

. . . . . . . . . . . . . . . . . . . . . . . . . . . 276
SRP vs. ISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
. . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
ISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282

21. . . . . . . . . . . . . . . . . . . . .

284

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
. . . . . . . . . . . . . . . . . . . . . . . . . . . 291
DIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
. . . . . . . . . . . . . . . . . . . . . 300
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304

13

14

22. . . . . . . . .

305

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
. . . . . . . . . . . . . . . . . . . . . 308
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

311

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

313

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316



.
, (DevDiv) Microsoft.
, , Programming Stuff1,
. 2011 Microsoft C# MVP,
Microsoft 2014 .
,
, - .
Sergey.Teplyakov@gmail.com.

SergeyTeplyakov.blogspot.ru.

, . ,
C#,
- .
:
,
.
. , , , , .
.
, , , , .
.NET Framework C#.
. C++
Java, , , .


, . ,
.
.

.
,
.
, .


, , , . , . , ,
.
, - ,
,
Sergey.Teplyakov@gmail.com.


, ,
, . ,
.

. ,
.
, ,
.
, .
, , , , , , ,
.

. , -
, ,
.
, . ,
!
,
. , ,
, , , ,
. , !


, sivchenko@minsk.piter.com ( , ).
!
http://www.piter.com
.


GoF- .NET
:
, , . ,
, ,
.
1990-
, ,
- 1-
. , , . ,
-1.
IoC- DI- (IoC Inversion of Control (
), DI Dependency Injection ( ))
.
2 ,
1

. -. // ., ..
.: , 2007. 288 .

, C# Java.

22

56.
, .
, , . ,

, . , ,
, - ,
, ? ,
,
.


, , . ?
,
. ,
.
1. , , ! , ! !
?
2. ! 1
! !
3. . , ,
. - , .
4. , , , , . , !
1


.
. .

, ,
. , ,
,
.
Abstract
SingletonProxyFactoryBean1 Hello, World, .1?
.1.
public class HelloWorld
{
public static void Main(String[] args)
{
MessageBody mb = new MessageBody();
mb.Configure("Hello World!");
AbstractStrategyFactory asf = DefaultFactory.Instance;
MessageStrategy strategy = asf.CreateStrategy(mb);
mb.Send(strategy);
}
}
, : ,
,
Design Patterns2, ,
. ,
.
1

shashdot: http://deve
lopers.slashdot.org/comments.pl?sid=33602&cid=3636102.

. ,
, , .

23

24

Design Patterns,
. , ,
.
,
.
, ,
.
, , ,
.
.


, ,
1. , ? , . , , .
, ,
.
, Loki2 ,
. , , , ,
.
1

, , .
, , . ,
.

. ++. .: , 2004. 336 .


loki : loki-lib.sourceforge.net.

vs.
,
/ . , , ,
, . ,
, , ,
.
.
.
,
.
, .
, , . , ,
. , .
,
.



, - , -
. . , .NET-: , .
. .NET-
,
.

25

26

,
, 20, ,
.NET- .NET Framework.

-
(full text search).
, Application Insights,
Microsoft.

1. (Strategy)

2. (Template Method)

3. (Mediator)

4. (Iterator)

5. (Observer)

6. (Visitor)

7.


(Strategy)
: , . , .
: .

,
, ,
, - .
, , ;
, , , . ,
, , , , /, (policy).
,
, -

1. (Strategy)

. ;
; ;
..1
-
.
- (.1.1), - , Elasticsearch
SQL Server.

. 1.1.

LogProcessor - : (LogFileReader), Windows (WindowsEvent


LogReader) ..
ILogReader, LogProcessor
.
:
.
.1.2.
:
Strategy (ILogReader) ;
Context (LogProcessor) ;
ConcreteStrategyA, ConcreteStrategyB (LogFileReader, Windows
EventLogReader) .
1

29

30

I.

.1.2.

, .
, , . AlgorithmInterface,
.
,
. , ,
.

.NET
,
.
( Sort ISortable) (Encode/Decode
IMessageProcessor).
,
.NET- . , ILogReader LogProcessor
Func<List<LogEntry>>,
(1.1).
1.1. LogProcessor
class LogProcessor
{
private readonly Func<List<LogEntry>> _logImporter;
public LogProcessor(Func<List<LogEntry>> logImporter)
{

1. (Strategy)

_logImporter = logImporter;
}
public void ProcessLogs()
{
foreach(var logEntry in _logImporter.Invoke())
{
SaveLogEntry(logEntry);
}
}
// ...
}
.NET.
,
.

. IStrategy IContext, .
, : , , .
.


:
;
.

,
. , , !

31

32

I.

, : - ,
.

.
.

- : . ,
. , .
IValidator
? IFactory IAbstractFactory,
? ,
( ) .
?
.
ILogReader LogProcessor ,
. LogProcessor
, , .
, .
, LogFile
Importer, , .

vs.
,

1. (Strategy)

. ,
.
, IComparable<T> Comparison<T>
(1.2).
1.2.
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
returnstring.Format("Id = {0}, Name = {1}", Id, Name);
}
}
class EmployeeByIdComparer : IComparer<Employee>
{
public int Compare(Employee x, Employee y)
{
return x.Id.CompareTo(y.Id);
}
}
public static void SortLists()
{
var list = new List<Employee>();
// ""
list.Sort(new EmployeeByIdComparer());
//
list.Sort((x, y) => x.Name.CompareTo(y.Name));
}

33

34

I.

- . List.Sort ,


, SortedList SortedSet (
1.3).

1.3. SortedSet
var comparer = new EmployeeByIdComparer();
// IComparable
var set = new SortedSet<Employee>(comparer);
// , Comparison<T>
,
Comparison<T> IComparable<T>
(1.4).

1.4. IComparer
class ComparerFactory
{
public static IComparer<T> Create<T>(Comparison<T> comparer)
{
return new DelegateComparer<T>(comparer);
}
private class DelegateComparer<T> : IComparer<T>
{
private readonly Comparison<T> _comparer;
public DelegateComparer(Comparison<T> comparer)
{
_comparer = comparer;
}

1. (Strategy)

public int Compare(T x, T y)


{
return _comparer(x, y);
}
}
}
(
1.5).
1.5. ComparerFactory
var comparer = ComparerFactory.Create<Employee>(
(x, y) => x.Id.CompareTo(x.Id));
var set = new SortedSet<Employee>(comparer);

Comparison<T> , ,
Enumerable.OrderyBy:
.

: ,
.
.
, . , . ,
1
.
, ,
.
1

IV .

35

36

I.

.NET Framework
.NET Framework.
LINQ (Language Integrated Query) , , .. , , , IComparer<T> IEqualityComparer<T>,
.
WCF : IErrorHandler
; IChannelInitializer ; IDispatchMessageFormatter
; MessageFilter ..
Windows Forms, WPF, ASP.NET
.
,
.


(Template Method)
: , .
: ,
.

- () . ,
,
(tight coupling) .
,

, Base Derived,
, .

38

I.


.
, : , ,
.
. , . ,
.
. .
1. .
2. .


(2.1).
2.1. LogReader
public abstract class LogReader
{
private int _currentPosition;
// ReadLogEntry :
public IEnumerable<LogEntry> ReadLogEntry()
{
return ReadEntries(ref _currentPosition).Select(ParseLogEntry);
}
protected abstract IEnumerable<string> ReadEntries(ref int position);
protected abstract LogEntry ParseLogEntry(string stringEntry);
}
. LogFileReader

2. (Template Method)

ReadEntries ParseLogEntry .
(framework)
, ,
.
.2.1.

. 2.1.

:
AbstractClass (LogReader) Template
Method (ReadLogEntry),
PrimitiveOperation1(), PrimitiveOperation2() .. (ReadEntries
ParseLogEntry);
ConcreteClass (LogFileReader) .
,
.

.NET

,
,

39

40

I.

.
. , , .
.NET-.
WCF-,
(2.2).
2.2. WCF
//
interface ILogSaver
{
void UploadLogEntries(IEnumerable<LogEntry> logEntries);
void UploadExceptions(IEnumerable<ExceptionLogEntry> exceptions);
}
// -
// WCF-
class LogSaverProxy : ILogSaver
{
class LogSaverClient : ClientBase<ILogSaver>
{
public ILogSaver LogSaver
{
get { return Channel; }
}
}
public void UploadLogEntries(IEnumerable<LogEntry> logEntries)
{
UseProxyClient(c => c.UploadLogEntries(logEntries));
}

2. (Template Method)

public void UploadExceptions(


IEnumerable<ExceptionLogEntry> exceptions)
{
UseProxyClient(c => c.UploadExceptions(exceptions));
}
private void UseProxyClient(Action<ILogSaver> accessor)
{
var client = new LogSaverClient();
try
{
accessor(client.LogSaver);
client.Close();
}
catch (CommunicationException e)
{
client.Abort();
throw new OperationFailedException(e);
}
}
}

, .

, WCF- ,
Closing the proxy and using statement
Programming WCF Services.


,
.
, : , ,

41

42

I.

, 1.



C#
(Extension Methods).
, :
, , .
,
,
.
.
(.2.2).

. 2.2. LogEntry

ToString() (2.3).
2.3.
public abstract class LogEntryBase
{
public DateTime EntryDateTime { get; internal set; }
1

2. (Template Method)

public Severity Severity { get; internal set; }


public string Message { get; internal set; }
// ExceptionLogEntry
public string AdditionalInformation { get; internal set; }
}
public static class LogEntryBaseEx
{
public static string GetText(this LogEntryBase logEntry)
{
var sb = new StringBuilder();
sb.AppendFormat("[{0}] ", logEntry.EntryDateTime)
.AppendFormat("[{0}] ", logEntry.Severity)
.AppendLine(logEntry.Message)
.AppendLine(logEntry.AdditionalInformation);
return sb.ToString();
}
}
.

.
,
(
/).

( /).
.
,
( ).

43

44

I.

. GetText
, .




- , .
-
LogFileReaderBase, .
(2.4).
2.4. LogFileReaderBase
public abstract class LogFileReaderBase : LogImporter, IDisposable
{
private readonly Lazy<Stream> _stream;
protected LogFileReaderBase(string fileName)
{
_stream = new Lazy<Stream>(
() => new FileStream(fileName, FileMode.Open));
}
public void Dispose()
{
if (_stream.IsValueCreated)
{
_stream.Value.Close();
}
}

2. (Template Method)

protected override sealed IEnumerable<string> ReadEntries(


ref int position)
{
Contract.Assert(_stream.Value.CanSeek);
if (_stream.Value.Position != position)
_stream.Value.Seek(position, SeekOrigin.Begin);
return ReadLineByLine(_stream.Value, ref position);
}
protected override abstract LogEntry ParseLogEntry(
string stringEntry);
private IEnumerable<string> ReadLineByLine(
Stream stream, ref int position)
{
// /
}
}
, .
,
.
,
.

vs.
, .
,
. , . , ,
(2.5).

45

46

I.

2.5. LogFileReaderBase, ILogParser


public interface ILogParser
{
LogEntry ParseLogEntry(string stringEntry);
}
public abstract class LogFileReaderBase : LogImporter
{
protected(string fileName, ILogParser logParser)
{
// ...
}
protected override LogEntry ParseLogEntry(string stringEntry)
{
return _logParser.ParseLogEntry(stringEntry);
}
// ...
}

, ,
.
LogParser,
. ,
ILogParser.


. , , , .
- ( , mock)
.

2. (Template Method)



(Extract and Override)1. , .
, LogFileReader .
MemoryStream
, Stream ( 2.6).
2.6.
public abstract class LogFileReaderBase : LogImporter, IDisposable
{
protected LogFileReaderBase(string fileName)
{
_stream = new Lazy<Stream>(() => OpenFileStream(fileName)));
}
protected virtual Stream OpenFileStream(string fileName)
{
return new FileStream(fileName, FileMode.Open);
}
}
//
class FakeLogFileReader : LogFileReaderBase
{
private readonly MemoryStream _mockStream;
public FakeLogFileReader(MemoryStream mockStream)
: base(string.Empty)
{
_mockStream = mockStream;
}
1

Working Effectively
With Legacy Code, The Art of Unit Testing.

47

48

I.

protected override Stream OpenFileStream(string fileName)


{
return _mockStream;
}
}
[Test]
public void TestFakedMemoryStreamProvidedOneElement()
{
// Arrange
LogFileReaderBase cut = new FakeLogFileReader(
GetMemoryStreamWithOneElement());
// Act
var logEntries = cut.ReadLogEntry();
// Assert
Assert.That(logEntries.Count(), Is.EqualTo(1));
}


: , , . -
,
. , , , .


,
, . , , .

.

2. (Template Method)


.
Code Contracts (2.7).
2.7.
[ContractClass(typeof (LogImporterContract))]
public abstract class LogImporter
{
protected abstract IEnumerable<string> ReadEntries(ref int position);
protected abstract LogEntry ParseLogEntry(string stringEntry);
}
[ExcludeFromCodeCoverage, ContractClassFor(typeof (LogImporter))]
public abstract class LogImporterContract : LogImporter
{
protected override IEnumerable<string> ReadEntries(ref int position)
{
Contract.Ensures(Contract.Result<IEnumerable<string>>() != null);
Contract.Ensures(
Contract.ValueAtReturn(out position) >=
Contract.OldValue(position));
throw new System.NotImplementedException();
}
protected override LogEntry ParseLogEntry(string stringEntry)
{
Contract.Requires(stringEntry != null);
Contract.Ensures(Contract.Result<LogEntry>() != null);
throw new System.NotImplementedException();
}
}

49

50

I.

Code Contracts
Contract, Requires, Ensures, Assume . ,
, ContractClassFor.

, ReadEntries ParseLogEntry null.
position
ReadEntries.


.
- ,
- . .NET
http://bit.ly/DesignByContractArticles, Code Contracts.

, , , .
, :
, ,
, ? ? ,
?


. , ,
.

.NET Framework
.NET Framework
. , , , .

2. (Template Method)

WCF .
CommunicationObject, Open, Close, Abort .
(sealed), OnClosed,
OnAbort ..
WCF ChannelBase,
ChannelFactoryBase, MessageHeader, ServiceHostBase, BodyWriter,

.
:
SafeHandle ( ) ReleaseHandle;
TaskScheduler QueueTask Try
ExecuteTaskInline;
HashAlgorithm HashCore, DbCommandBuilder
.

(Dispose Pattern)
.NET
, .
++ , , C#,
Dispose IDisposable,
.
(Dispose Pattern) .NET
.
? , ,
,
, , ..
( ) .
: ,
.

,
. ,
(CLR, Common Language Runtime).
,
IntPtr. ,
.
.NET IDisposable,
Dispose ,

51

52

I.

(finalizers), .
Dispose ,
,
1. ,
.

(non-sealed) .
Dispose(bool),

(2.8).
2.8.
public class ComplexResourceHolder : IDisposable
{
// ( )
private IntPtr _buffer;
// ( )
private SafeHandle _handle;
public ComplexResourceHolder()
{
//
_buffer = AllocateBuffer();
_handle = new SafeWaitHandle(IntPtr.Zero, true);
}
protected virtual void Dispose(bool disposing)
{
//
ReleaseBuffer(_buffer);
// Dispose,
1

, . .
, ,
CriticalFinalizerObject.

Thread, ReaderWriterLock SafeHandle.

2. (Template Method)

if (disposing)
{
if (_handle != null)
_handle.Dispose();
}
}
~ComplexResourceHolder()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// AllocateBuffer ReleaseBuffer
}
,
.
Dispose(bool),
Dispose ,
, .
Dispose ,
.
, ,
,
,
.
. -,
, -, 99,999% .
, :
?
FileStream IntPtr?

53

54

I.

,
?
, ,
, , SmartHandle.

, SmartHandle
.
- ,
Dispose(bool)
.
:
DisposeNativeResources
DisposeManagedResources.
2.9.
public class ProperComplexResourceHolder : IDisposable
{
//
protected virtual void DisposeNativeResources()
{
ReleaseBuffer(_buffer);
}
protected virtual void DisposeManagedResources()
{
if (_handle != null)
_handle.Dispose();
}
~ProperComplexResourceHolder()
{
DisposeNativeResources();
}
public void Dispose()
{

2. (Template Method)

DisposeNativeResources();
DisposeManagedResources();
GC.SuppressFinalize(this);
}
// AllocateBuffer ReleaseBuffer
}
Dispose ,

, .
,
, .

Dispose, Dispose Pattern bit.ly/Dispose


PatternDotNet.
DG Update: Dispose, Finalization and Resource Management
http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resourcemanagement/.

SafeHandle

, .NET Framework,
.
SafeHandle.
, Dispose(bool), SafeHandle
ReleaseHandle,
,
IsInvalid, , .
, ,
SafeHandle ( 2.10)
.
2.10. SafeHandle
// HativeHelper
class CustomSafeHandler : SafeHandle
{
private readonly IntPtr _nativeHandle =

55

56

I.

NativeHelper.InvalidHandler;
[ReliabilityContract(
Consistency.WillNotCorruptState, Cer.MayFail)]
public CustomSafeHandler()
: base(NativeHelper.InvalidHandler, true)
{
_nativeHandle = NativeHelper.AcquireHandle();
}
public override bool IsInvalid
{
[SecurityCritical]
get
{
return
_nativeHandle == NativeHelper.InvalidHandler;
}
}
protected override bool ReleaseHandle()
{
NativeHelper.ReleaseHandle(DangerousGetHandle());
return true;
}
}
ReleaseHandle Dispose
, ,
( IsInvalid false).

.
.

.


(Mediator)
: , .
: ,
.
, .

. LogFile
Reader - LogSaver, - 1 (.3.1).
1

, , http://www.object
mentor.com/resources/articles/dip.pdf. ,
(Lamp) (Button). , ,
. ,
.

58

I.



   


 




 

 

. 3.1. -

LogFileReader LogSaver, LogFileReader .


LogFileReader, .
, .

- .
,
. ,
.
: , , ,
.
, LogImporter,
(.3.2).
LogImporter :
. ,
. ,
,
! LogFileReader LogImporter, LogFileSaver
.

3. (Mediator)







    



   
 
    


 
 

 

. 3.2. -

Domain-Driven Design. Tackling Complexity in


the Heart of Software (flexible) (supple)
. (, ),
.
.
, .
, , .
(premature generalization).

,
.
.3.3.
(
System.Object) -. .
:
Mediator (LogFileImporter) . , Mediator
;

59

60

I.

. 3.3.

ConcreteCollegue1, ConcreteCollegue2 (LogFileReader, LogFile


Saver) ,
.


,
. ( high
cohesion), ( low coupling).
.
,
. / ,
. / .
.
,
.
,
:

.

3. (Mediator)



, .

/ (Producer/Consumer), (Event
Aggregator) ,
.
.
, .
. LogFileReader LogFileSaver LogImporter. ,
.
( push-
1), .
(.3.4).
LogFileReader , .
IObservable .

. .
Windows Forms UI-. : -.

(CustomForm) TextBox
Button
TextBox ( 3.1).
1

Push- pull- 5.

61

62

I.

 
  
  









 




 

 
  

. 3.4.

3.1. Windows Forms


public CustomForm()
{
InitializeComponent();
buttonSave.Enabled = false;
textBoxName.TextChanged += (s,ea) =>
{
buttonSave.Enabled = true;
};
}



. ,
.

3. (Mediator)

, , ,
. ,
, , , .
. , . , , . ,
, .
.
( LogImporter), LogFileReader LogSaver,

(Event Aggregator) (.3.5).








 

   


   
   




. 3.5.

LogFileReader / , . LogSaver
, , .
, ,
. , . ,
.

63

64

I.

, . , , . ,
, .
, A . , ,
, .
,
, .
,
.

? !

: -? TDD (TestDriven Development) , ?
, ,
, . .
, ,
.
. .
? , ,
. ,
, .
(mocks) ,
.
, ,
(CUT Class Under Test) .

, (, -

3. (Mediator)

), .

(bit.ly/StubsVsMocks) Stubs are not Mocks (http://martinfowler.com/articles/mocks


ArentStubs.html).


. -, -,
, .
: ,
.
, / - . , .
, (.3.6).

. 3.6.

65

66

I.

Main, ServiceMain
global.asax. (Composition Root)
.
IoC-
-.

. , ,
, , .
: . .
, , , .


, .
,
. , , , .
.
, , ,
. ,
, :
.

.NET Framework
, ,

3. (Mediator)

.NET Framework . .NET- .


Windows Forms ,
:
- .
EventAggregator, WPF ,

.
MVC (Model View Controller, ) MVP (Model View Presenter, ), Controller Presenter 1.
Producer/Consumer (/)
. ,
. .NET Framework
BlockingCollection.

MVx- ,
21, .

67


(Iterator)
: , .


. , , -.
,
.

, . : ,
, .
,
: foreach C#,
range-for C++ 11, for Java 5+, Eiffel

4. (Iterator)

across. ,
foreach ,
(Iterator Block C# VB) (Sequence Comprehension),
F#, Scala, Phyton .
. ,
, LogFileReader
LogFileSource, IEnumerable<LogEntry>
(4.1).
4.1. LogFileSource
public class LogFileSource : IEnumerable<LogEntry>
{
private readonly string _logFileName;
public LogFileSource(string logFileName)
{
_logFileName = logFileName;
}
public IEnumerator<LogEntry> GetEnumerator()
{
foreach (var line in File.ReadAllLines(_logFileName))
{
yield return LogEntry.Parse(line);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
, .NET
Framework .

69

70

I.

Design Patterns, Aggregate


IEnumerable<T>, Iterator IEnumerator<T>
Iterator, (.4.1, 4.2).




  







 

 



 





 




. 4.1.

:
Iterator (IEnumerator<T>) ;
Aggregate (IEnumerable<T>) ,
;
ConcreteAggregate1 (List<T>) ;
ConcreteIterator (List.Enumerator<T>)
.

.NET .
GetEnumerator IEnumerable, .
IEnumerator :
MoveNext . false,
;
Current ;
Reset . .










 


 
 




 

. 4.2. .NET Framework

 




4. (Iterator)

71

72

I.

1- ,
MoveNext .
.NET , ++. ++
: Input Forward Bidirectional RandomAccess. ++
OutputIterator, .
.NET : .
.NET,
(generics) (iterator
blocks) (.4.3).

. 4.3.

C#/.NET
. .
,
, Code Contracts. ,
, ,
, remarks,
.

4. (Iterator)

Code Contracts
BCL. IEnu
merable/IEnumerator , .
MoveNext Current
(4.2).
4.2. .NET
public T Current
{
get
{
Contract.Requires(!Disposed, "Iterator should not be disposed.");
Contract.Requires(IteratorPointsToCorrectValue,
"MoveNext() should be called and return 'true'.");
Contract.Ensures(true, "Returns current value from the
Aggregate.");
// ,
return default(T);
}
}
public bool MoveNext()
{
Contract.Requires(!Disposed, "Iterator should not be disposed.");
Contract.Requires(Valid, "Iterator should

be valid.");

// ,
//
Contract.Ensures(Finished() ||
InternalIndex == Contract.OldValue(InternalIndex) + 1);
Contract.Ensures(Contract.Result<bool>() ==

73

74

I.

(InternalIndex < InternalLength));


return default(bool);
}

, ,
, ! ,
mscorlib.Contracts.dll, .

Current
:

Dispose;

:
MoveNext, true.

: Current ,
. , Contract.Ensures(true, ""). ,
null .
MoveNext
:

Dispose;

(
).

: ,
true,
false.
. -,
Current MoveNext.
Current : Current
Dispose MoveNext !
,
Current .
, MoveNext:
MoveNext . MoveNext

4. (Iterator)

false! , , ( ).
.
, MoveNext.
1 (4.3).
4.3.
public static IEnumerator<int> CustomArrayIterator(this int[] array)
{
foreach (var n in array) { yield return n; }
}
,
, .

yield return. ,
, .

, Reset
. , ,
. Reset?

C# ,
( 1- ), (
) ,
. (corouting)2,
MoveNext.
1

C#. 1,
http://bit.ly/IteratorPartOne.

, https://ru.wikipedia.org/wi
ki/.

75

76

I.


, , :
,
MoveNext. ,
, , (4.4).
4.4.
public static IEnumerable<string> ReadFromFile(string path)
{
if (path == null) throw new ArgumentNullException("path");
foreach(string line in File.ReadLines(path))
{
yield return line;
}
}
// ?
var result = ReadFromFile(null); //1
foreach (var l in result)
{
Console.WriteLine(l); //2
}
LINQ (Language Integra
ted Query),
.
C#,
C#, http://bit.ly/IteratorsInCSharp.
.

foreach
foreach /
.

4. (Iterator)

(/) while.
(4.5).
4.5. foreach
public static void ForEachIEnumerable(IEnumerable sequence)
{
// foreach(var e in sequence) {Console.WriteLine(e);}
IEnumerator enumerator = sequence.GetEnumerator();
object current = null;
try
{
while (enumerator.MoveNext())
{
current = enumerator.Current;
Console.WriteLine(current);
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}

foreach IEnumerable/
IEnumerable<T>. , GetEnu
merator, bool MoveNext()
Current.
Duck typing, foreach.

, foreach
C#5.0, current

77

78

I.

(
C# 5.01).
IDisposable,
IEnumerator<T> IDisposable. ,
, , , finally, Dispose . ,
,
IEnumerable/IEnumerator, IDisposable.


, () (
). , ,
.
4.6.
4.6.
public static IEnumerable<int> GenerateFibonacci()
{
int prev = 0;
int current = 1;
while (true)
{
yield return current;
int tmp = current;
current = prev + current;
prev = tmp;
}
}
1

http://bit.ly/ClosingOverLoopVariable.

4. (Iterator)

C# (list
compreh ension),
.


, ++, ( )
, , . , ,
:
, .
, ,
.NET Framework. , , : . , 4.7
InvalidOperationException.
4.7. .NET
var list = new List<int> { 42, 12 };
var listIter = list.GetEnumerator();
listIter.MoveNext();
list.RemoveAt(1); // 2-
Console.WriteLine(listIter.Current); // OK
listIter.MoveNext(); // InvalidOperationException
var linked = new LinkedList<int>();
linked.AddLast(42);
var linkedIter = linked.GetEnumerator();
linkedIter.MoveNext();
linked.AddLast(12);
Console.WriteLine(linkedIter.Current); // OK
linkedIter.MoveNext(); // InvalidOperationException

79

80

I.

++,
std::list .


.NET Framework .
, , , , .
(4.8), , .
4.8.
var x = new {Items = new List<int> {1, 2, 3}.GetEnumerator()};
while (x.Items.MoveNext())
{
Console.WriteLine(x.Items);
}
, ,
. , ,
-. Roslyn,
- ! (Roslyn. How to Contribute,
Coding Conventions.)


.
2. Observable.Generate 1.

Push-based-
,
, , , .
(pull-based) ,
Next .
1

http://bit.ly/ObservableGenerate.

4. (Iterator)

push-based-,
, .
, , .NET Reactive Extensions
IObserver<T>/IObservable<T>. ,
, , (4.9).
4.9. IObservable
var list = new List<int> {1, 2, 3};
IObservable<int> observable = list.ToObservable();
observable.Subscribe(
onNext: n => Console.WriteLine("Processing: {0}", n),
onCompleted: () => Console.WriteLine("Sequece finished"));
, , , SqlDataReader, IEnume
rable, 1.

, .
-?
: LogFileReader IEnume
rable<LogEntry Read() LogFileSource, IEnumerable<LogEntry>?
,
. LogFileSource ,
, , .
?
1

Introduction to Rx. 5, .

81

82

I.

, MoveNext?
LogFileReader.

StackOverflow.com : Why not inherit from List, , FootballTeam


List<Player>. ,
FootballTeam List<Player>. , , .

.NET Framework
.NET Framework :
IEnumerable/IEnumerator
( );
IEnumerable<T>/IEnumerator<T> ( );
IObservable<T>/IObserver<T> ( pushbased) .
C# foreach,
.


(Observer)
:
,
.
: .


.
1 2 -
. 2
, .
2 ,
- .
2 1 .
pull-, push-
(.5.1).

84

I.



 


 





 

  

   

 

. 5.1. Pull- push-

Push- . push-
(callbacks). , , push-
. push .

-
.
- LogFileReader.
. LogFileReader
- Read
(pull-). LogFileReader - (push-).
push-. LogFileReader
LogSaver, - . LogFileReader

, , .
LogFileReader
LogSaver, ,
.

5. (Observer)

:

.
.5.2.

. 5.2.

:
Observer ;
Subject ( ) ;
ConcreteObserver ;
ConcreteSubject .
.NET
.
, IObserver/IObservable
.

C# .NET Java,
-. Java :
object notify/notifyAll
(BaseSubject)
(BaseObserver).

85

86

I.


.NET:
( );
(events);
-;
IObserver/IObservable.


.NET
. ,
(5.1).
5.1. LogFileReader
public class LogFileReader : IDisposable
{
private readonly string _logFileName;
private readonly Action<string> _logEntrySubscriber;
private readonly static Timespan CheckFileInterval =
Timespan.FromSeconds(5);
private readonly Timer _timer;
public LogFileReader(string logFileName,
Action<string> logEntrySubscriber)
{
Contract.Requries(File.Exists(logFileName));
_logEntrySubscriber = logEntrySubscriber;
_timer = new Timer(() =>
CheckFile(), CheckFileInterval, CheckFileInterval);
}
public void Dispose()
{

5. (Observer)

_timer.Dispose();
}
private void CheckFile()
{
foreach(var logEntry in ReadNewLogEntries())
{
_logEntrySubscriber(logEntry);
}
}
private IEnumerable<string> ReadNewLogEntries()
{
// ...
// ,
//
}
}
.
.NET , 1:1 LogFileReader .
, , , .

,
. .NET ( )
.
,
,
(5.2).

87

88

I.

5.2. LogFileReader
public class LogEntryEventArgs : EventArgs
{
public string LogEntry {get; internal set;}
}
public class LogFileReader : IDisposable
{
private readonly string _logFileName;
public LogFileReader(string logFileName)
{
//...
}
public event EventHandler<LogEntryEventArgs> OnNewLogEntry;
private void CheckFile()
{
foreach(var logEntry in ReadNewLogEntries())
{
RaiseNewLogEntry(logEntry);
}
}
private void RaiseNewLogEntry(string logEntry)
{
var handler = OnNewLogEntry;
if (handler != null)
handler(this, new LogEntryEventArgs(logEntry));
}
}
.
LogFileReader

5. (Observer)

- . ,
.



. ,
, (
5.3).
5.3.
public interface ILogFileReaderObserver
{
void NewLogEntry(string logEntry);
void FileWasRolled(string oldLogFile, string newLogFile);
}
public class LogFileReader : IDisposable
{
private readonly ILogFileReaderObserver _observer;
private readonly string _logFileName;
public LogFileReader(string logFileName,
ILogFileReaderObserver observer)
{
_logFileName = logFileName;
_observer = observer;
}
// , ,
// -
// .
private void DetectThatNewFileWasCreated()
{
//

89

90

I.

if (NewLogFileWasCreated())
_observer.FileWasRolled(_logFileName, GetNewLogFileName());
}
}

, . , .

IObserver/IObservable

: (not composable).
, .
pull-based- LogFileReader LINQ (Language Integrated Query)
.
, LINQ
, :
//
var messages =
logFileReader.Read()
.Select(ParseLogMessage)
.Where(m => m.Severity == Critical);
foreach(var criticalMessages in messages.Buffer(10))
{
BulkSaveMessages(criticalMessages);
}
Buffer Enumerable,
.
4- .NET Framework IObserver/IObser
vable ,

5. (Observer)

(Rx, Reactive Extensions). IObservable LINQ-.


push-,
LogFileReader :
public class LogFileReader : IDisposable
{
private readonly string _fileName = fileName;
private readonly Subject<string> _logEntriesSubject =
new Subject<string>();
public LogFileReader(string fileName)
{
_fileName = fileName;
}
public void Dispose()
{
//
CloseFile();
// ,
_logEntriesSubject.OnComplete();
}
public IObservable<string> NewMessages
{
get { return _logEntriesSubject; }
}
private void CheckFile()
{
foreach(var logEntry in ReadNewLogEntries())
{

91

92

I.

_logEntriesSubject.OnNext(logEntry);
}
}
}
LINQ-:
var messagesObservable =
logFileReader.NewMessages
.Select(ParseLogMessages)
.Where(m => m.Severity == Critical);
messagesObservable
.Buffer(10)
.Subscribe(IList<LogEntry> criticalMessages => BulkSaveMessages(critical
Messages));

1 . IObservable ,
, IEnumerable, .
pull-based,
,
push-based, .
4.

IObserver/IObservable

. IObservable ,
.
(OnNext), ,
(OnError), ,
(OnComplete). IObservable ,
.
1

. Introduction to Rx .

5. (Observer)



IObserver/IObservable. ,
pushbased-, LINQ-. ,
.
Subject<T> -
(Observable.FromEvent) . .


,
.
:
.
1:1
. :
, .
Task, ,
, .
, - .

?
.
, .

93

94

I.

?

. .
.
.
, IObservable.

.NET.
, ..
, -, , . , ( Form.OnClosing TaskScheduler.UnobservedException),
, .
?
.
, .
pull- .
?

.

. ,

5. (Observer)

, . , LogFileReader,
(ILogFileReaderObserver),
(, ILogFileProcessor).
?
.
?
API .


: push pull1.
push-
: EventArgs, . pull-
, .
push- pull-
.NET.
.NET Event
Handler<T>, : object sender TEventArgs
args:
public class LogEntryEventArgs : EventArgs
{
public string LogEntry {get; internal set;}
}

Push/pull- . push- ,
. .
push/pull- , .

95

96

I.

public class LogFileReader : IDisposable


{
private readonly string _logFileName;
public string LogFileName { get { return _logFileName; } }
public event EventHandler<LogEntryEventArgs> OnNewLogEntry;
// ...
}
//
public class LogForwarder
{
public LogForwarder(LogFileReader logFileReader)
{
logFileReader.OnNewLogEntry += HandleNewLogEntry;
}
private void HandleNewLogEntry(object sender, LogEntryEventArgs ea)
{
var logEntry = ea.LogEntry;
var logFile = ((LogFileReader)sender).LogFileName;
// logEntry
}
}


, EventHandler. .NET
EventHandler<T>.

(push)
, , ,
(pull) .

5. (Observer)

. push pull-
. Push- ,
, ,
. Pull- ,

, .
pull- , UI- , . - push-
,
.


.NET-. , , , :
public class Singleton
{
private static readonly Singleton _instance = new Singleton();
public static Singleton Instance { get { return _instance; } }
public event EventHandler Event;
}
class MemoryLeak
{
public MemoryLeak()
{
Singleton.Instance.Event +=
(s, e) => Console.WriteLine("Hello, Memory Leak!");
}
}

97

98

I.

MemoryLeak
, Singleton.MyEvent.
.
1. , .
3. IDisposable
Dispose.
4. (Weak Event Pattern). , (Weak
References) .
,
.


.
.
. .
/
. ,
(,
) .
. ,
,
.
:
,
.

5. (Observer)


. MVx (Model View Controller/Presenter View
Model)
. .

MVx 21.

.NET Framework
. .NET Framework
, .
.
(AppDomainSetup.AppDomainInitializer, HttpConfi
guration.Initializer) ( WPF/Windows Forms/WCF).
. API Event Hub . IEventProcessor Close
Async, OpenAsync ProcessEventsAsync.

99


(Visitor)
: ,
. ,
.

-
. , , .
.
, ,
. , .
, . , -,
, .
(.6.1).

6. (Visitor)


+DateTime
+Severity
+Message

ExceptionLogEntry

SimpleLogEntry

+Exception

+AdditionalInfo

. 6.1. LogEntry

-. ,
,

.. , . , LogEntry

. /
, , .
- . (6.1).
6.1. LogEntry
public class DatabaseLogSaver
{
public void SaveLogEntry(LogEntry logEntry)
{
var exception = logEntry as ExceptionLogEntry;
if (exception != null)
{
SaveException(exception);
}

101

102

I.

else
{
var simpleLogEntry = logEntry as SimpleLogEntry;
if (simpleLogEntry != null)
SaveSimpleLogEntry(simpleLogEntry);
throw new InvalidOperationException("Unknown log entry type");
}
}
private void SaveSimpleLogEntry(SimpleLogEntry logEntry) {...}
private void SaveException(ExcetpionLogEntry exceptionLogEntry) {...}
}
LogEntry ,

.
.
LogEntry Accept,

ILogEntryVisitor,
Visit (6.2).
6.2.
public interface ILogEntryVisitor
{
void Visit(ExceptionLogEntry exceptionLogEntry);
void Visit(SimpleLogEntry simpleLogEntry);
}
public abstract class LogEntry
{
public abstract void Accept(ILogEntryVisitor logEntryVisitor);
//
}

6. (Visitor)

public class ExceptionLogEntry : LogEntry


{
public override void Accept(ILogEntryVisitor logEntryVisitor)
{
//
// Visit(ExceptionLogEntry)
logEntryVisitor.Visit(this);
}
}
, - ,
ILogEntryVisitor ( 6.3).
6.3.
public class DatabaseLogSaver : ILogEntryVisitor
{
public void SaveLogEntry(LogEntry logEntry)
{
logEntry.Accept(this);
}
void ILogEntryVisitor.Visit(ExceptionLogEntry exceptionLogEntry)
{
SaveException(exceptionLogEntry);
}
void ILogEntryVisitor.Visit(SimpleLogEntry simpleLogEntry)
{
SaveSimpleLogEntry(simpleLogEntry);
}
private void SaveException(ExceptionLogEntry logEntry) {...}
private void SaveSimpleLogEntry(SimpleLogEntry logEntry) {...}
}

103

104

I.


.
.6.2.

Client





ConcreteVisitor1

ConcreteVisitor2

+Visit(ConcreteElementA)
+Visit(ConcreteElementB)

+Visit(ConcreteElementA)
+Visit(ConcreteElementB)

ObjectStructure


 

v.VisitConcreteElementA(this)
ConcreteElementA

ConcreteElementB

+Accept(Visitor v)
+OperationA()

+Accept(Visitor v)
+OperationA()

v.VisitConcreteElementB(this)

. 6.2.

:
Visitor (ILogEntryVisitor) ;
Element (LogEntry) ,
;
Client (DatabaseLogSaver)
.

6. (Visitor)

, . Shape
,
. Rectangle
: , .. , .

.
. Draw
, GetArea
..
- ,
.
.
.

. IVisitor
. , .

18.

.
:
Accept. IVisitor, .

vs.
,
. Accept

105

106

I.

Match, .
Match1 LogEntry ,
c 6.4.
6.4.
public abstract class LogEntry
{
public void Match(
Action<ExceptionLogEntry> exceptionEntryMatch,
Action<SimpleLogEntry> simpleEntryMatch)
{
var exceptionLogEntry = this as ExceptionLogEntry;
if (exceptionLogEntry != null)
{
exceptionEntryMatch(exceptionLogEntry);
return;
}
var simpleLogEntry = this as SimpleLogEntry;
if (simpleLogEntry != null)
{
simpleEntryMatch(simpleLogEntry);
return;
}
throw new InvalidOperationException("Unknown LogEntry type");
}
}

Match (
6.5).
1

T Match<T>(), Func<EceptionLogEntry, T> Func<SimpleLogEntry, T>.

6. (Visitor)

6.5.
public class DatabaseLogSaver
{
public void SaveLogEntry(LogEntry logEntry)
{
logEntry.Match(
ex => SaveException(ex),
simple => SaveSimpleLogEntry(simple));
}
private void SaveSimpleLogEntry(SimpleLogEntry logEntry) {...}
private void SaveException(ExceptionLogEntry exceptionLogEntry) {...}
}

, Match
/.
,
/.
18.


1 (pattern matching).
-
, - .
, 1


,
, . switch .
C# .

, Pattern Matching in C#
Part0. C# .
, ( ) .

107

108

I.

, ,
- . :
.
, , - , .

Match,
,
. Match
, Log
EntryEx.



. . Accept
: .
,
: (6.6).
6.6.
LogEntry logEntry = new ExceptionLogEntry();
ILogEntryVisitor visitor = new Visitor1();
// Visitor1.Visit(ExcpetionLogEntry)
logEntry.Accept(visitor);
logEntry = new SimpleLogEntry();
visitor = new Visitor2();
// Visitor2.Visit(SimpleLogEntry)
logEntry.Accept(visitor);

6. (Visitor)

vs.
IVisitor.
, .
Visit(YetAnotherType).
VisitorBase
, Visit.
, Visit .
, .NET .
IVisitor VisitorBase.

( 6.7).
6.7.
public abstract class LogEntryVisitorBase : ILogEntryVisitor
{
public virtual void Visit(ExceptionLogEntry exceptionLogEntry)
{}
public virtual void Visit(SimpleLogEntry simpleLogEntry)
{}
}
public class DatabaseExceptionLogEntrySaver : LogSaverBase
{
public void SaveLogEntry(LogEntry logEntry)
{
logEntry.Accept(new ExceptionLogEntryVisitor(this));
}
private void SaveException(ExceptionLogEntry exceptionLogEntry) {...}

109

110

I.

private class ExceptionLogEntryVisitor : LogEntryVisitorBase


{
private readonly DatabaseExceptionLogEntrySaver _parent;
public ExceptionLogEntryVisitor(
DatabaseExceptionLogEntrySaver parent)
{
_parent = parent;
}
// ExceptionLogEntry
public override void Visit(ExceptionLogEntry exceptionLogEntry)
{
_parent.SaveException(exceptionLogEntry);
}
}
}
DatabaseExceptionLogEntrySaver
LogEntryVisitorBase, .
, LogEntryVisitorBase
.

, . .

,
.

.
,
, .

6. (Visitor)


,
.
, , .
. ,

, . .

.NET Framework
ExpressionTreeVisitor
(Expression Trees) .NET Framework.
LINQ-, .
Roslyn . CSharpSyntaxVisitor , SymbolVisitor<TResult>
.
DbExpressionVisitor Entity Framework SQL-.

111

.
.
.
.
.
, .
.

.
,
, , .


: , ,
, .

7.


.
. ,
, , .

ICommand Execute, (.7.1).

. 7.1.

Invoker ( ) , Receiver ( ViewModel).


.
. , SimplifyBinaryConditionCommand .
, ,
.
.
- , C#
.
,
. , ,
(7.1).

113

114

I.

7.1.
public class LogExporterViewModel
{
public Action GetExportLogsCommand()
{
return () => _logSaver.Save(LogEntries);
}
public IEnumerable<LogEntry> LogEntries {get; private set;}
}

ICommand RelayCommand, Func<T> Action1.
.NET Framework:
ICommand WPF,
;
IDbCommand ADO.NET ,
;
Task<T> Func<T>,
,
.


:
. ,
.

. Socket
Connect, , (
1

WPF MVVM
WPF (MSDN Magazine, 2009. ).

7.

Thread) , .
.


(.7.2).









  

  





. 7.2.

(Socket)
State, ConcreteState1 (NotConnected)
ConcreteState2 (Connected) Handle
( Connect).
. . ,

, . , ,
, .
, Thread, Thread .
. .NET Framework
,
(public) .NET Framework .
CommunicationObject WCF : Created, Opening, Opened, Closing, Closed Faulted.

115

116

I.

Task :
Created, WaitingForActivation, WaitingToRun, Running, RunT o
Completion, Canceled, Faulted.


: ,
. - , .
.NET
Framework, , .
, ,
Handle()
Handled True.
Windows Forms Closing, (
7.2).
7.2.
public DialogForm()
{
this.Closing += HandleClosing;
}
private void HandleClosing(object sender, CancelEventArgs ea)
{
if (UserDontWantToCloseTheWindow())
{
ea.Cancel = true;
}
}
.NET ,
.
Invoke, (7.3).

7.

7.3.
// Form.cs
private void ClosingForm()
{
if (Closing != null)
{
var eventArgs = new CancelEventArgs(cancel: false);
var invocationList = Closing.GetInvocationList();
foreach (EventHandler<CancelEventArgs> handler in invocationList)
{
handler(this, eventArgs);
if (eventArgs.Cancel)
{
//
return;
}
}
}
CloseForm();
}
.7.3.

 










 

 

. 7.3.

117

118

I.

.NET Framework:
Closing Windows Forms
Cancel CancelEventArgs True;
TaskScheduler.UnobservedException, , , UnobservedTaskException
EventArgs.SetObserved.
Contract.ContractFailed Application.DispatcherUnhandled
Exception.

II

8. (Singleton)

9. (Abstract Factory)

10. (FactoryMethod)

11. (Builder)

120

II.

-
. , ,
. ,
.
.
,
. , ,
. - ,
.
, .
,
, .
,
.
,
.
.

. , . ,
.
, .
.
.
. , -

II.


. .
. . ,
, , . , , . ,
.
.
, .

121


(Singleton)
: , , .
: - .

.
, , .
,
.
,
. ,
.
- ,
.

8. (Singleton)

.8.1.






 
 

 
   

. 8.1.

.NET

, ( ,
.NET) :
;
1 .
,
.NET- .
.


, .
( )
. , ,
.

Lazy of T
(8.1),
( ).
1

,
.

123

124

II.

8.1. Lazy<T>
public sealed class LazySingleton
{
private static readonly Lazy<LazySingleton> _instance =
new Lazy<LazySingleton>(() => new LazySingleton());
LazySingleton() {}
public static LazySingleton Instance { get { return _instance.Value; } }
}
,
Singleton<T>, .
: + + !
: .NET 4.0+.



(8.2), .
8.2.
public sealed class DoubleCheckedLock
{
// volatile!
private static volatile DoubleCheckedLock _instance;
private static readonly object _syncRoot = new object();
DoubleCheckedLock()
{}
public static DoubleCheckedLock Instance
{
get
{

8. (Singleton)

if (_instance == null)
{
lock (_syncRoot)
{
if (_instance == null)
{
_instance = new DoubleCheckedLock();
}
}
}
return _instance;
}
}
}
, , _instance volatile!
, ,
Instance, ,
.
. _instance = new DoubleCheckedLock(); , () .
1. .
2. ( ).
3. _instance.
_instance volatile,
. 2- 3-
, ,
_instance , 1 (.8.2).
1

Publication
via Volatile Field The C# Memory Model in Theory and Practice
(MSDN Magazine, 2012. ).

125

126

II.





   



   



 
 





   

 


. 8.2.

:
+ ;
;
.NET Framework.
:
+ ;
.


8.3.
8.3.
public sealed class FieldInitSingleton
{
// ,
//

8. (Singleton)

private static readonly FieldInitSingleton _instance =


new FieldInitSingleton();
FieldInitSingleton() {}
//
// beforefieldinit
static FieldInitSingleton() {}
public static FieldInitSingleton Instance { get { return _instance; } }
}
8.4.
8.4.
public sealed class LazyFieldInitSingleton
{
private LazyFieldInitSingleton() {}
public static LazyFieldInitSingleton Instance
{
get { return SingletonHolder._instance; }
}
//
private static class SingletonHolder
{
public static readonly LazyFieldInitSingleton _instance =
new LazyFieldInitSingleton();
// ,
// _instance Instance
// LazyFieldSingleton
}
}

127

128

II.

8.5.

(readonly field).
8.5.
class FieldBasedSingleton
{
public static readonly FieldBasedSingleton Instance =
new FieldBasedSingleton();
}
.
1. .
,
TypeInitializationException. ,
,
.
2. . ,
.
, beforeFieldInit,
(relaxed)
.
, 8.6 ( ) Main,
.
8.6.
static void Main(string[] args)
{
Console.WriteLine("Starting Main...");
if (args.Length == 1)
{
var s = SingletonWithoutStaticCtor.Instance;
}
Console.ReadLine();
}

8. (Singleton)

, .
, , , . ,
.

3. . .
,
,
.
: .
:
;
( );
.
? .8.3.


?
, , ,
, . , , ,
,
.

Singleton vs. Ambient Context



, .
: .
Singleton , . , .

129

130

II.

. 8.3.

-
, , .

, . ,
,
Ambient Context1 (8.7).
,
Instance . setter , ,
-.
1

Ambient Context The Dependency Injection


in .NET.
Ambient Context: http://bit.ly/AmbientContext.

8. (Singleton)

,
.
8.7. Ambient Context
public interface ILogger
{
void Write();
}
internal class DefaultLogger : ILogger
{
public void Write() {}
}
public class GlobalLogger
{
private static ILogger _logger = new DefaultLogger();
// ( )
//
public static ILogger Logger
{
get { return _logger; }
internal set { _logger = value; }
}
}
, , .
Instance
(non-sealed) , .
SingletonBase , , .
:
.

131

132

II.

,
. Ambient Context
( ) , .

.

Singleton vs. Static Class


-
.
, .
?
:
. , .
:
1 .
ThreadPool.QueueUserWorkItem .


, ,
: ,
, . ,
.
1: ,
, , . (, Instance),
1

III.

8. (Singleton)

(AnotherInstance?) , GetInstance(name) .
-
. : , .
,
(.8.4).






 
 

  





  

. 8.4. ,

,
(DataUploader) Program.
2:
,
.
.
, ,
. , ,
, .
, .
. .

133

134

II.

/
( ?!), :
- . ,
, ? , ,
.
.
.
, . , ,
.

:
, ,
, . ,
, .
.
,
.
. Ambient Context, , ,
-.
.
/. ,
. , , .
, -, -
.
.
, -

8. (Singleton)

.
(
8.8).
8.8.
// ,
// , ,
private static IRepository _repository = Repository.Instance;
, , , -
.

.NET Framework
.
.NET Framework : Sy
stem.ServiceModel.Dispatcher.PeerValidationBehavior.Instan
ce, System.Net.NetworkingPerfCounters.Instance, System.Threa
ding.TimerQueue.Instance ..
SystemClock.Instance
NodaTime SqlClientFactory.Instance .NET Framework.
.
ThreadPool.QueueUserWorkItem, log4net.LogManager.GetLogger
..
( Ambient Context).
: AppDomain.Cur
rentDomain, Thread.CurrentThread, SynchronizationContext.Cur
rent, TaskSceduler.Defult, Form.ActiveForm, HttpContext.Current,
OperationContext.Current ..
: ASP.NET MVC
ControllerBuilder.Current, Entity Framework Database.SetInitia
lizer.
, .NET Framework

, .
,

135

136

II.

.
( ThreadPool.QueueUserWorkItem)
( Ambient Context)

.


Skeet Jon. Implementing the Singleton Pattern in C#. http://csharpindepth.com/
articles/general/singleton.aspx.
Programming Stuff: . http://bit.ly/Sing
letonsAndStaticCtor.
Programming Stuff: . http://bit.ly/Sta
ticCtors.
Programming Stuff: . http://bit.ly/De
pendencyManagement.
. The C# Memory Model in Theory and Practice. MSDN Magazine,
2012. .


(Abstract Factory)
. :
,
.
, .
,
.
: (dependent or related objects),
.
:
.

138

II.

.
, . - ,
.
, (Application Root). Main (
),
.
.
-
. , SQL Server, .
(), LogSaver DbProviderFactory
ADO.NET (9.1).
9.1.
public class LogSaver
{
private readonly DbProviderFactory _factory;
public LogSaver(DbProviderFactory factory)
{
_factory = factory;
}
public void Save(IEnumerable<LogEntry> logEntries)
{
using (var connection = _factory.CreateConnection())
{

9. (Abstract Factory)

SetConnectionString(connection);
using (var command = _factory.CreateCommand())
{
SetCommandArguments(logEntries);
command.ExecuteNonQuery();
}
}
}
private void SetConnectionString(DbConnection connection)
{}
private void SetCommandArguments(IEnumerable<LogEntry> logEntry)
{}
}
DbProviderFactory,
SqlClientFactory, SQL Server, Npgsql
ConnectionFactory, PostgreSql.
DbProviderFactory , (DbCon
nection), (DbCommand), (DbDataAdapter) .,
.
.9.1.
:
AbstractFactory (DbProviderFactory) ( ) ;
AbstractProductA, AbstractProductB (DbCommand, DbConnection) ,
;
ProductA1, ProductB1 (SqlConnection, NpgsqlConnection) ;
Client (LogSaver) , .

139















. 9.1.

 

 


 









140
II.

9. (Abstract Factory)



, , .

, : /, /, / ..
,
.
, .
1 .
: ? ?


.
. ,

SQL Server. SqlClient
Factory LogSaver (9.2).
9.2.
public static void Main(string[] args)
{
var saver = new LogSaver(SqlClientFactory.Instance);
var loader = new LogFileLoader(args[0]);
saver.Save(loader.Load());
}
. , .
.
1

I.

141

142

II.

DbProviderFactory : DbProviderFactories.Get
Factory1 (9.3).
9.3.
public static void Main(string[] args)
{
var saver = new LogSaver(GetDbProviderFactory());
var loader = new LogFileLoader(args[0]);
saver.Save(loader.Load());
}
private static DbProviderFactory GetDbProviderFactory()
{
const string factoryName = "System.Data.SqlClient";
return DbProviderFactories.GetFactory(factoryName);
}

.


.
, ADO.NET DbProviderFactory
.
, .
,
,
(9.4).
9.4.
class GenericAbstractFactory
{
public object Make(string id) { ... }
1

9. (Abstract Factory)

public IProduct MakeProduct(string id) { ... }


public T MakeGeneric<T>(string id) where T : IProduct { ... }
}
,
( IProduct).
DI- (Dependency Injection Containers IoC Inversion of Control Containers),
Unity, StructureMap1 . .
,
.
,
.

.
:
.
, , .
, .
.
1. ,
.
1

.
DI- Dependency Injection in .NET.
DI-. Service Locator (http://bit.ly/Service
LocatorPattern).

143

144

II.

2. . .
3. , .

.NET Framework
DbProviderFactory ADO.NET Create
Command(): DbCommand, CreateConnection(): DbConnection .
CodeDomProvider CreateGenerator():
ICodeGenerator, CreateCompiler(): ICodeCompiler, CreateParser():
ICodeParser.
SymetricAlgorithm CreateEncryptor():
ICryptoTransform CreateDecryptor(): ICryptoTransform.

10


(FactoryMethod)
, .
: ,
, .
.

,
, .
,

.
- LogFileReader , , LogEntry (ExceptionLogEntry SimpleLogEntry
) .
,
.

146

II.

, . LogReaderBase,
- ( Stream) ,
LogEntryParser,
LogEntry (10.1).
10.1.
public static class LogEntryParser
{
public static LogEntry Parse(string data)
{
// data
// : ExceptionLogEntry SimpleLogEntry
}
}
public abstract class LogReaderBase
{
public IEnumerable<LogEntry> Read()
{
using (var stream = OpenLogSource())
{
using (var reader = new StreamReader(stream))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
yield return LogEntryParser.Parse(line);
}
}
}
}
protected abstract Stream OpenLogSource();
}

10. (FactoryMethod)

LogReaderBase, LogImporter,
- .
-
MemoryStreamLogReader, ,
.
. OpenLog
Source ,
, . LogEntry
Parser ,
.

.


:
;
;
.


.10.1.

. 10.1.

147

148

II.


, .
:
Creator (LogReaderBase)
. ;
ConcreteCreator (LogFileReader) ,
ConcreteProduct (FileStream);
Product (Stream) , ;
ConcreteProduct (FileStream) .


,
(.10.2).

. 10.2.

,
, , Create.


,
(.10.3).

10. (FactoryMethod)

. 10.3.


.NET ,
.


switch,
. , (, ..), ,
.
, ,
, (10.2).
10.2.
static class ImporterFactory
{
private static readonly Dictionary<string, Func<Importer>> _map =
new Dictionary<string, Func<Importer>>();
static ImporterFactory()
{
_map[".json"] = () => new JsonImporter();
_map[".xls"] = () => new XlsImporter();
_map[".xlsx"] = () => new XlsImporter();
}

149

150

II.

public static Importer Create(string fileName)


{
var extension = Path.GetExtension(fileName);
var creator = GetCreator(extension);
if (creator == null)
throw new UnsupportedImporterTypeException(extension);
return creator();
}
private static Func<Importer> GetCreator(string extension)
{
Func<Importer> creator;
_map.TryGetValue(extension, out creator);
return creator;
}
}
_map,
Create.


,
:

? :
C# ,
, . - , ,
.

10. (FactoryMethod)


. Better Construction with Factories (Journal of Object
Technology, 2002. http://www.jot.fm/issues/issue_2007_07/article3.pdf).

C# (generics),
(reflection) (10.3).
10.3.
public abstract class Product
{
protected internal abstract void PostConstruction();
}
public class ConcreteProduct : Product
{
//
// .
internal ConcreteProduct() {}
protected internal override void PostConstruction()
{
Console.WriteLine("ConcreteProduct: post construction");
}
}
// Product
public static class ProductFactory
{
public static T Create<T>() where T : Product, new()
{
try
{
var t = new T();

151

152

II.

//
t.PostConstruction();
return t;
}
catch (TargetInvocationException e)
{
//
var edi = ExceptionDispatchInfo.Capture(e.InnerException);
edi.Throw();
// , !
return default(T);
}
}
}
10.4.
10.4.
var p1 = ProductFactory.Create<ConcreteProduct>();
var p2 = ProductFactory.Create<AnotherProduct>();
Create TargetInvocati
onException. new T()
T, T TargetInvocationExce
ption. , Create
ExceptionDispatchInfo1.

TargetInvocationException new T() (leaky abstractions).



ExceptionDispatchInfo .
,
http://bit.ly/ExceptionRethrowing.
1

ExceptionDispatchInfo .NET 4.5.

10. (FactoryMethod)


.
. ,
.

,
.
.

. . , , ,
.


.
, ,
.
LogReaderBase
LogFileReader.
. LogReaderBase
LogReader , FromFile
FromStream (.10.4).

LogReader
: OpenLogSource Stream FromStream From
File.

, ,
.

153

154

II.


   

     

  

  


 


    

    





. 10.4.


,
, . , ,
. , LogReader,
LogFileReader StreamLogReader, , OpenLogStream Func<Stream>
(10.5).
10.5. LogReader
public class LogReader
{
private readonly Func<Stream> _streamFactory;
private LogReader(Func<Stream> streamFactory)
{
_streamFactory = streamFactory;
}

10. (FactoryMethod)

public static LogReader FromFile(string fileName)


{
Func<Stream> factory =
() => new FileStream(fileName, FileMode.Open);
return new LogReader(factory);
}
public static LogReader FromStream(Stream stream)
{
Func<Stream> factory = () => stream;
return new LogReader(factory);
}
public IEnumerable<LogEntry> Read()
{
using (var stream = OpenLogSource())
{
using (var reader = new StreamReader(stream))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
yield return LogEntryParser.Parse(line);
}
}
}
}
private Stream OpenLogSource()
{
return _streamFactory();
}
}

155

156

II.

Func
Func<Stream> . Func<T> .
(internal)
. ,
Func<Stream>, , Func<int, string,
int, ValidationResult> factory . ,
.

vs.
-
.
, .
. C#
, . Timespan, .
, , ,
,
double, . Timespan
(10.6).
10.6.

public struct Timespan


{
public Timespan(double ticks) { ... }
public static Timespan FromMilliseoncds(double value) {...}
public static Timespan FromSeconds(double value) {...}
public static Timespan FromMinutes(double value) {...}
//
}

10. (FactoryMethod)

. ,
. ,
1.
, .
,
.
,
.


. ,
, , .
.


.
, .
.
. , TaskFactory Task Parallel Library
1

, if
.
bloated constructor, , !

157

158

II.

, ..
,
.


.
, WebRequest.Create(string) LogReader,
.
. , , . , Timespan.FromSeconds, Timespan.From
Milliseconds ..
. ,

,

.
. , . ,
, .
. , ,
.
. , .

.NET Framework
.NET Framework .
: Stream.CreateWaitHandle, Security
Attribute.CreatePermission, ChannelFactory.CreateChannel,
XmlNode.CreateNavigator.

10. (FactoryMethod)

: IControllerFactory ASP.NET MVC, IHttp


HandlerFactory ASP.NET, ServiceHostFactory IChannelFactory<T>
WCF, IQueryProvider LINQ.
: TaskFactory TPL.
: Activator.CreateInstance, Array.Crea
teInstance, StringComparer.Create.
: RandomNumberGenerator.Create, WebRequest.Crea
te, BufferManager.CreateBufferManager, Message.CreateMessage, Mes
sageFault.CreateFault.
: File.Create, File.CreateText.
: Timespan.FromSecond, Timespan.From
Milliseconds, GCHandle.FromIntPtr, Color.FromArgb.

159

11

(Builder)
: ,
.


. , ,
.
,
. ,
, .
, ,
.
.
Email
. Email ,

11. (Builder)

, (attachment)
.. ,
, MailMessage .NET
Framework, Mail
MessageBuilder ( 11.1).
11.1.
public sealed class MailMessageBuilder
{
private readonly MailMessage _mailMessage = new MailMessage();
public MailMessageBuilder From(string address)
{
_mailMessage.From = new MailAddress(address);
return this;
}
public MailMessageBuilder To(string address)
{
_mailMessage.To.Add(address);
return this;
}
public MailMessageBuilder Cc(string address)
{
_mailMessage.CC.Add(address);
return this;
}
public MailMessageBuilder Subject(string subject)
{
_mailMessage.Subject = subject;
return this;
}

161

162

II.

public MailMessageBuilder Body(string body, Encoding enconding)


{
_mailMessage.Body = body;
_mailMessage.BodyEncoding = enconding;
return this;
}
public MailMessage Build()
{
return _mailMessage;
}
}
( 11.2).
11.2. MailMessageBuilder
var mail = new MailMessageBuilder()
.From("st@unknown.com")
.To("support@microsof.com")
.Cc("my_boss@unknown.com")
.Subject("Msdn is down!")
.Body("Please fix!", Encoding.UTF8)
.Build();
new SmtpClient().Send(mail);
C ,
.
,
, .
, . .11.1.

11. (Builder)





 


  



  


 





  


  

. 11.1.

:
Builder ;
Director , ,
;
ConcreteBuilder ,
Product.
: , Product
(ConcreteBuilder). , ( Director) .
,
, Json.
. ?
? ,
Director, ?
, (.11.2).
,
. Director ( MailMessageBuilder) Build.
Builder (MailMessageBuilder)
(MailMessage).

163

164

II.

. 11.2.

.NET
.NET :
(fluent interface) .


(11.3).
, ,
.
11.3.
var result = Enumerable.Range(1, 10).Select(n => n + 1).Count();
Java
-DSL (Domain-Specific Language). ,
(11.4).
11.4. StringBuilder
public override string ToString()
{
return new StringBuilder()
.AppendFormat("Id: {0}", Id).AppendLine()

11. (Builder)

.AppendFormat("Name: {0}", Name).AppendLine()


.ToString();
}


, .
, .
MailMessageBuilder
MailMessage ( 11.5).
11.5.
public static class MailMessageBuilderEx
{
public static MailMessage From(this MailMessage mailMessage,
string address)
{
mailMessage.From = new MailAddress(address);
return mailMessage;
}
public static MailMessage To(this MailMessage mailMessage,
string address)
{
mailMessage.To.Add(address);
return mailMessage;
}
public static MailMessage Cc(this MailMessage mailMessage,
string address)
{
mailMessage.CC.Add(address);
return mailMessage;
}
public static MailMessage Subject(

165

166

II.

this MailMessage mailMessage, string subject)


{
mailMessage.Subject = subject;
return mailMessage;
}
public static MailMessage Body(this MailMessage mailMessage,
string body, Encoding enconding)
{
mailMessage.Body = body;
mailMessage.BodyEncoding = enconding;
return mailMessage;
}
}
Mail
MessageBuilder ( 11.6).
11.6.
var mail = new MailMessage()
.From("st@unknown.com")
.To("support@microsof.com")
.Cc("my_boss@unknown.com")
.Subject("Msdn is down!")
.Body("Please fix!", Encoding.UTF8);
new SmtpClient().Send(mail);
, , .

.
:
, . Build,
.

11. (Builder)


,
. ,
.
.NET Framework, MailMessageBuilder , , ..
,
. Builder, . , IBuilder, , .


. , MailMessageBuilder
MailMessage . Build (, InvalidOperationException), To
( 11.7).
11.7. Build
public MailMessage Build()
{
if (_mailMessage.To.Count == 0)
{
throw new InvalidOperationException(
"Can't create a mail message with empty To. Please call
'To' method first");
}
return _mailMessage;
}

167

168

II.


, .
.
( 11.8).
11.8. MailMessageBuilder
public class MailMessageBuilder
{
public MailMessageBuilder(string address)
{
To(address);
}
//
, , 34. ,
.
.
. ,
. Build ,
.
( 11.9).
11.9.
public class MailMessageBuilder
{
private readonly MailMessage _mailMessage = new MailMessage();
internal MailMessageBuilder(MailMessage mailMessage)
{
_mailMessage = mailMessage;
}
public FinalMailMessageBuilder To(string address)
{

11. (Builder)

_mailMessage.To(address);
//
return new FinalMailMessageBuilder(_mailMessage);
}
//
}
public class FinalMailMessageBuilder
{
private readonly MailMessage _mailMessage;
internal FinalMailMessageBuilder(MailMessage mailMessage)
{
_mailMessage = mailMessage;
}
public MailMessage Build()
{
return _mailMessage;
}
}
Final
MailMessageBuilder, To
. , Build
.

,
.
Build InvalidOperationException
, , .
. .

169

170

II.


. , (immutable).
,
(, ) .
.NET , .NET Framework
StringBuilder, .

, 1. . 11.10
ImmutableList<int>.
11.10.
var list = ImmutableList<int>.Empty;
foreach (var element in Enumerable.Range(1, 10))
{
// list 10 !
list = list.Add(element);
}
,
,
( 11.11).
11.11.
ImmutableList<int>.Builder builder =
ImmutableList<int>.Empty.ToBuilder();
foreach (var element in Enumerable.Range(1, 10))
{
1

.NET Framework, . nuget


System.Collections.Immutable for .NET 4.0.

11. (Builder)

builder.Add(element);
}
ImmutableList<int> list = builder.ToImmutable();


.
ImmutableList<T>
. Immutable
List<T>.Builder,
ImmutableList<T>.
,
. . MailMessage
, ( 11.12).
11.12. MailMessage
public class MailMessage
{
private string _to;
private string _from;
private string _subject;
private string _body;
private MailMessage()
{}
public static MailMessageBuilder With()
{
return new MailMessageBuilder(new MailMessage());
}
public string To { get { return _to; } }
public string From { get { return _from; } }

171

172

II.

public string Subject { get { return _subject; } }


public string Body { get { return _body; } }
public class MailMessageBuilder {...}
}
MailMessage With, . MailMessageBuilder MailMessage, ,
( 11.13).
11.13.
// MailMessage
public class MailMessageBuilder
{
private readonly MailMessage _mailMessage;
internal MailMessageBuilder(MailMessage mailMessage)
{
_mailMessage = mailMessage;
}
public MailMessageBuilder To(string to)
{
_mailMessage._to = to;
return this;
}
public MailMessageBuilder From(string from)
{
_mailMessage._from = from;
return this;
}
public MailMessageBuilder Subject(string subject)
{

11. (Builder)

_mailMessage._subject = subject;
return this;
}
public MailMessageBuilder Body(string body)
{
_mailMessage._body = body;
return this;
}
public MailMessage Build()
{
return _mailMessage;
}
}
MailMessage
MailMessage, (
11.14).
11.14.
var mailMessage =
MailMessage.With()
.From("st@unknown.com")
.To("support@microsof.com")
.Subject("Msdn is down!")
.Body("Please fix!")
.Build();
Console.WriteLine(mailMessage.To);

, ,
, .

173

174

II.

, .
,
.
,
,
(, , , ), , JSON Xml,
Fluent API ..
.

. , .

.NET Framework
.NET Framework.
StringBuilder, UriBuilder, DbCommandBuilder DbConnectionStrin
gBuilder ADO.NET.
ImmutableList<T>.Builder, Immuta
bleDictionary<TKey, TValue>.Builder ..
Reflection.Emit: ModuleBuilder, TypeBuilder, EnumBuilder,
MethodBuilder ..
WCF : ChannelBuilder,
DispatcherBuilder, EndpointAddressBuilder ..
autofac, IoC-, .

-
, ,
- .
, .
(bit.ly/OnAutomatedTesting).

11. (Builder)

-
. , , ,
. , :
.
, ,
.
, .
, ,
. :
, (
AAA Arrange, Act, Assert).
, ,
, , .
,
LogEntryReader,
-.

-
LogEntryReader /
, -.
StreamReader ILogEntryParser (
11.5).
11.5. LogEntryReader
public interface ILogEntryParser
{
bool TryParse(string s, out LogEntry logEntry);
}
public class SimpleLogEntryParser : ILogEntryParser
{
// -
public bool TryParse(string s, out LogEntry logEntry)
{
// ...
}
}
public class LogEntryReader
{

175

176

II.

private readonly Stream _stream;


private readonly ILogEntryParser _logEntryParser;
public LogEntryReader(Stream stream, ILogEntryParser logEntryParser)
{
_stream = stream;
_logEntryParser = logEntryParser;
}
public IEnumerable<LogEntry> Read()
{
using (var sr = new StreamReader(_stream))
{
string line;
while ((line = sr.ReadLine()) != null)
{
LogEntry logEntry;
if (_logEntryParser.TryParse(line, out logEntry))
{
yield return logEntry;
}
}
}
}
}
LogEntryReader ,
, .
MemoryStream, ,
, .
, 11.6.
11.6.
[Test]
public void Test_Stream_With_One_Entry()
{

11. (Builder)

// Arrange
var memoryStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memoryStream);
sw.WriteLine("[2014/11/01][Info] This is message!");
sw.Flush();
memoryStream.Position = 0;
ILogEntryParser logEntryParser = new SimpleLogEntryParser();
var reader = new LogEntryReader(memoryStream, logEntryParser);
// Act
var entries = reader.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
LogEntry entry = entries.Single();
Assert.That(entry.EntryDateTime,
Is.EqualTo(new DateTime(2014, 11, 01)));
Assert.That(entry.Severity, Is.EqualTo(Severity.Info));
Assert.That(entry.Message, Is.EqualTo("This is message!"));
}

.
, , .
, .
, -:
, .

. Xunit
, NUnit , SetUp
(11.7).
11.7. SetUp
private LogEntryReader _classUnderTest;
[SetUp]
public void SetUp()
{

177

178

II.

var memoryStream = new MemoryStream();


StreamWriter sw = new StreamWriter(memoryStream);
sw.WriteLine("[2014/11/01][Info] This is message!");
sw.Flush();
memoryStream.Position = 0;
ILogEntryParser logEntryParser = new SimpleLogEntryParser();
_classUnderTest = new LogEntryReader(memoryStream, logEntryParser);
}
[Test]
public void Test_Stream_With_One_Entry()
{
// Act
var entries = _classUnderTest.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
LogEntry entry = entries.Single();
Assert.That(entry.EntryDateTime,
Is.EqualTo(new DateTime(2014, 11, 01)));
Assert.That(entry.Severity, Is.EqualTo(Severity.Info));
Assert.That(entry.Message, Is.EqualTo("This is message!"));
}
,
. (Arrange),
(Act) (Assert) .
,
, ,
.


SetUp
(coupling) ,
.

.

11. (Builder)

,

(11.8).
11.8.
public static LogEntryReader CreateLogEntryReader(string content)
{
var memoryStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memoryStream);
sw.WriteLine(content);
sw.Flush();
memoryStream.Position = 0;
ILogEntryParser logEntryParser = new SimpleLogEntryParser();
return new LogEntryReader(memoryStream, logEntryParser);
}
[Test]
public void Test_Stream_With_One_Entry()
{
// Arrange
var classUnderTest = CreateLogEntryReader(
"[2014/11/01][Info] This is message!");
// Act
var entries = classUnderTest.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
LogEntry entry = entries.Single();
Assert.That(entry.EntryDateTime,
Is.EqualTo(new DateTime(2014, 11, 01)));
Assert.That(entry.Severity, Is.EqualTo(Severity.Info));
Assert.That(entry.Message, Is.EqualTo("This is message!"));
}

179

180

II.

,
. CreateLogEntryReader
,
.
, .
SetUp
, ,
.

.

.
. . , , .
300 , 300 .
, ,
. ,
, .

Test Fixture
,
.

ILogEntryParser
,
.
.
,
.
Fixture ,
11.9.
11.9. LogEntryReaderFixture
// LogEntryReader
internal class LogEntryReaderFixture
{
private ILogEntryParser _parser = new SimpleLogEntryParser();

11. (Builder)

private readonly Lazy<LogEntryReader> _lazyCut;


private string _streamContent;
public LogEntryReaderFixture()
{
_lazyCut = new Lazy<LogEntryReader>(
() => LogEntryReaderTestFactory.Create
(_streamContent, _parser));
}
public LogEntryReaderFixture WithParser(ILogEntryParser parser)
{
_parser = parser;
return this;
}
public LogEntryReaderFixture WithStreamContent(string streamContent)
{
_streamContent = streamContent;
return this;
}
public LogEntryReader LogEntryReader
{
get { return _lazyCut.Value; }
}
}
, ,
: ,
(11.10).
11.10. LogEntryReaderFixture
[Test]
public void Test_Stream_With_One_Entry()
{

181

182

II.

// Arrange
var classUnderTest = new LogEntryReaderFixture()
.WithParser(new SimpleLogEntryParser())
.WithStreamContent("[2014/11/01][Info] This is message!")
.LogEntryReader;
// Act
var entries = classUnderTest.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
}
LogEntryReaderFixture
. ,
.

Fixture , ,
AutoFixture,
. AutoFixture , . AutoFixture IoC-,
Unity, StructureMap ., .
github: github.com/AutoFixture.

-

, .
, - ,
LogEntry.

, .
-
-
.

, ,

11. (Builder)

. NUnit TestCaseSource,
, :
(11.11).
11.11.
[TestCaseSource("SimpleLogEntrySource")]
public LogEntry Test_SimpleLogEntry_Parse(string logEntry)
{
// Arrange
var parser = new SimpleLogEntryParser();
// Act
LogEntry result = parser.Parse(logEntry);
// Assert
return result;
}
, Simple
LogEntrySource (11.12).
11.12.
//
private static TestCaseData Entry(string entry)
{
return new TestCaseData(entry);
}
private static IEnumerable<TestCaseData> SimpleLogEntrySource()
{
yield return
Entry("[2014/01/12] [DEBUG] message")
.Returns(new SimpleLogEntry(DateTime.Parse("2014-01-12"),
Severity.Debug, "message"));
yield return
Entry("[2015/01/12] [Info] another message")

183

184

II.

.Returns(new SimpleLogEntry(DateTime.Parse("2015/01/12"),
Severity.Info, "another message"));
yield return
Entry("corrupted message")
.Throws(typeof(InvalidOperationException));
}
NUnit TestCaseData, ,
(
TestCaseData), ( Returns)
( Throws).
Entry,
.

,
. -

.

-
- http://bit.ly/Parametrized
UnitTests.

III

12. (Adapter)

13. (Facade)

14. (Decorator)

15. (Composite)

16. (Proxy)

186

III.

.
, Main,
, .

, , .
, ,
. , , ,
, . ,
, , . .
,
.
.
,
.

. ,
, ,
.

.
, c
.
, .
.
,
.
:

III.


.
.
.
,
TCP , 1. , WCF .NETRemoting,
-,
.

,
. WCF TCP- ,
-, .

187

12


(Adapter)
: ,
. .

. , .
.
-.
, , .
SqlServer,
SqlServerLogSaver. , , Elasticsearch. , ElasticsearchLogSaver,
, ,
(.12.1).

12. (Adapter)





 
 
    
 

  

     





. 12.1. SqlServerLogSaver ElasticsearchLogSaver

( ), ( ).
ILogSaver. , , , (.12.2).












  
 
 
 





  


 





. 12.2. -

. , , ,
(12.1).

189

190

III.

12.1. SqlServerLogSaverAdapter
public class SqlServerLogSaverAdapter : ILogSaver
{
private readonlySqlServerLogSaver _sqlServerLogSaver =
new SqlServerLogSaver();
public void Save(LogEntrylogEntry)
{
var simpleEntry = logEntry as SimpleLogEntry;
if (simpleEntry != null)
{
_sqlServerLogSaver.Save(simpleEntry.EntryDateTime,
simpleEntry.Severity.ToString(),
simpleEntry.Message);
return;
}
varexceptionEntry = (ExceptionLogEntry) logEntry;
_sqlServerLogSaver.SaveException(
exceptionEntry.EntryDateTime, exceptionEntry.Message,
exceptionEntry.Exception);
}
}
,
.
.12.3.
Client

void Request() {
adaptee.SpecificRequest()
}

Target

Adaptee



+SpecificRequest()

Adapter
+Request()

. 12.3.

12. (Adapter)

:
Target (ILogSaver) ,
;
Adaptee (SqlServerLogSaver) , ;
Adapter (SqlServerLogSaverAdapter) -, ;
Client ( ILogSaver) , .


, , . ,
.


. .
,
, .
.
,
. ,

(.12.4).
, ,
.
C# , .
(.12.5).

191

192

III.






  
 


  

  









  











. 12.4.
 









  



 















. 12.5.

, . , ,
.


.
.

12. (Adapter)

, . ,
LogSaver, , .
, , , .
1. IAsyncLogSaver .
2. AsyncLogSaverAdapter,
IAsyncLogSaver, .
3. LogSaver ,
.
4. .
5. AsyncLogSaverAdapter .
(.12.6).

. 12.6.

193

194

III.

, ,
. AsyncLogSaverAdapter , (
12.2).
12.2. AsyncLogSaverAdapter
public interface IAsyncLogSaver
{
Task SaveAsync(LogEntrylogEntry);
}
public class AsyncLogSaverAdapter : IAsyncLogSaver
{
private readonlyLogSaver _logSaver;
public AsyncLogSaverAdapter(LogSaverlogSaver)
{
_logSaver = logSaver;
}
public Task SaveAsync(LogEntrylogEntry)
{
return Task.Run(() => _logSaver.Save(logEntry));
}
}


C# . , LINQ- fromsinobj
Select, Where, OrderBy ., .
foreach
GetEnumerator, boolMoveNext Current. async/await GetA waiter

12. (Adapter)

GetResult1. IEnumerable<T> ( IEnumerable) Add.


,
, - . 6- C#, Add ( 12.3).
12.3. CustomCollection
public class CustomCollection : IEnumerable<int>
{
private readonly List<int> _list = new List<int>();
public void Insert(int value)
{
_list.Add(value);
}
public IEnumerator<int>GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static class CustomCollectionExtensions
{
public static void Add(this CustomCollectioncustomCollection, int value)
{
1

(ducktyping) .

195

196

III.

customCollection.Insert(value);
}
}
CustomCollectionExtensions
, CustomCollection ( 12.4).
12.4. CustomCollection
//
// !
varcc = newCustomCollection {42};

.
.
, , .
.
.
,
.

.NET Framework
TextReader/TextWriter Stream / /.
BinaryReader/BinaryWriter /.
ReadonlyCollection<T> (IList<T>)
(IReadonlyCollection<T>).
LINQ- ( IQueryProvider)
,
IQueryProvider.

13

(Facade)
: .
, .

.
ADO.NET , (output)
. ,
. ,
, , .
,
, ,
.
,
SQLServer (.13.1).

198

III.




  
   
   
    
    


 

 

  

 

 

  



 

  
 

  
 

. 13.1. SQLServer


, ,
. SqlServerFacade
, : ,
ADO.NET.
.13.2.

. 13.2.

13. (Facade)

:
Facade (SqlServerFacade) , ;
Client , ,
.


,
,
. , . ,
; ,
.


, .
. , . .
.
, ,
.
.
, . 1
.


,
. ,
1

12.

199

200

III.

, ,
.
, SqlServer SqlServer
Provider Configuration,
( 13.1).
13.1.
public static IDbCommandCreateCommand(Configuration config) {...}

. (coupling) , ,
, .
,
. ,
(log4net, NLog, .NETTraces)
. , ,
, .

.NET Framework
XmlSerializer , .
ThreadPool.QueueUserWorkItem .
Parallel TPL . ,
(partitioning) Task<T> .
System.Runtime.CompilerServices.RuntimeHelpers
, ..
System.Console -.

14


(Decorator)
: .
.

,
. , , 1, , ,
?
, .
.
1


.
, . , .
. ,
.

202

III.

.
Windows-,
,
1.

.
, , (throttling).
,
.
( 14.1).
14.1.
public interface ILogSaver
{
Task SaveLogEntry(string applicationId, LogEntrylogEntry);
}
public sealed class ElasticsearchLogSaver : ILogSaver
{
public Task SaveLogEntry(string applicationId, LogEntrylogEntry)
{
// Elasticsearch
return Task.FromResult<object>(null);
}
}
public abstract class LogSaverDecorator : ILogSaver
{
protected readonly ILogSaver _decoratee;

ApplicationInsights
Microsoft, , . ApplicationInsights API
- , , .

14. (Decorator)

protected LogSaverDecorator(ILogSaver decoratee)


{
_decoratee = decoratee;
}
public abstract Task SaveLogEntry(
string applicationId, LogEntry logEntry);
}
, (ILogSaver)
: - (Elastic
searchLogSaver) -, , . ,

( 14.2).
14.2. ThrottlingLogSaverDecorator
public class ThrottlingLogSaverDecorator : LogSaverDecorator
{
public ThrottlingLogSaverDecorator(ILogSaverdecoratee)
: base(decoratee)
{}
public override async Task SaveLogEntry(
string applicationId, LogEntrylogEntry)
{
if (!QuotaReached(applicationId))
{
IncrementUsedQuota();
// . !
await _decoratee.SaveLogEntry(applicationId, logEntry);
return;
}

203

204

III.

// ! !
throw new QuotaReachedException();
}
private boolQuotaReached(string applicationId)
{
// ,
}
private void IncrementUsedQuota()
{
//...
}
}
(ThrottlingLogSaverDecorator)
, , ( decoratee).
,
. QuotaReached
Exception, 1.
ILogSaver
. ,
, ( 14.3).
14.3.
ILogSaverlogSaver = new ThrottlingLogSaverDecorator(
new ElasticsearchLogSaver());
var controller = new LogSaverController(logSaver);
1

- , HTTP,
429 TooManyRequests,
.

14. (Decorator)

.14.1.





 

 


 




 

 
 


   

   

 

 
 

 
 
 
 

. 14.1.

:
Component (ILogSaver) ,
;
Client (LogSaverController) , ;
ConcreteComponent (ElasticsearchLogSaver)
;
Decorator (LogSaverDecorator) , ;
ConcreteDecoratorA (ThrottlingLogSaverDecorator) , .


vs.
-
.

205

206

III.

ElasticsearchLogSaver
(.14.2).



 
 










 







. 14.2.

, . ThrottleElasticsearchLog
Saver
ILogSaver.
ILogSaver,
.
, .
, .
, , ( 14.4).
14.4.
//
public class TraceLogSaverDecorator : LogSaverDecorator
{
publicTraceLogSaverDecorator(ILogSaver decoratee) : base(decoratee)
{}

14. (Decorator)

public override async Task SaveLogEntry(string applicationId,


LogEntry logEntry)
{
var sw = Stopwatch.StartNew();
try
{
await _decoratee.SaveLogEntry(applicationId, logEntry);
}
finally
{
Trace.TraceInformation(" {0}",
sw.ElapsedMilliseconds);
}
}
}
ILogSaver logSaver = new ThrottlingLogSaverDecorator(
new TraceLogSaverDecorator(new ElasticsearchLogSaver()));
// logSaver


.
,
Main. IoC- .
, , ( 14.5).
14.5. ILogSaver
public static class LogSaverFactory
{
public static ILogSaverCreateLogSaver()
{

207

208

III.

return
new ThrottlingLogSaverDecorator(
new TraceLogSaverDecorator(
new ElasticsearchLogSaver()));
}
}
, .
.


, , .
. ,

.
. , , . , ,
.
. , ,
. , , , .


IoC-, Unity StructureMap, (Interceptors). IL- (IntermediateLanguage) ,
.
. ,
( ?)
Unityinterceptors .

14. (Decorator)

.
, . , .

, .
:
;
;
;
;
/, ..
,
, .

.
, ,
ApplicationInsights .
, . Task
(http://bit.ly/CachedDecorator).

.NET Framework
.NETFramework . /, .

209

210

III.

System.IO.BufferedStream /.
System.IO.Compression.GZipStream, System.IO.Compression.Def
lateStream /.
System.CodeDom.Compiler.IndentedTextWriter System.IO.TextWriter.
System.Reflection.TypeDelegator System.Type.
System.Collections.SortedList.SyncSortedList ,
SortedList
lock.

/ .NET
/ ,
.
TextReader, StreamReader, StringReader .
,
.
System.IO,
(.14.3).
/ .
/: System.IO.Stream
FileStream, MemoryStream, NetworkStream .

/ .
(BufferedStream, GZipStream .).
/, , ..
, WCF,
.
( TextReader/TextWriter Binary
Reader/BinaryWriter).
/,
.
. File ,
.
/ ,
(File.OpenRead, File.OpenWrite, File.Create, File.Append
Text, File.OpenText .).





 

 







+ReadByte(): int
+WriteBite(in b: byte)

Stream





 

DataStream






  

  





  


  






 



+Write(in c: char)
+WriteLine(in s: string)

TextWriter

. 14.3. System.IO

+BaseStream: Stream

StreamDecorator






 



+Read(): int
+ReadLine(): string

TextReader





 



14. (Decorator)

211

212

III.


/ ,
. TextReader/TextWriter
, , StreamReader/
StreamWriter, /,
StringReader/StringWriter, .
,
/, TextReader/TextWriter
1 ( 14.6).
14.6. LogEntryParser
public class LogEntryParser
{
private readonly TextReader _reader;
public LogEntryParser(TextReader reader)
{
_reader = reader;
}
public IEnumerable<LogEntry> Parse()
{
string line;
while ((line = _reader.ReadLine()) != null)
{
yield return ParseLine(line);
}
}
private LogEntry ParseLine(string line)
{
1

StreamReader
.
.

14. (Decorator)

return new SimpleLogEntry();


}
}

StringReader ( 14.7).
14.7. LogEntryParser
[TestFixture]
class LogEntryParserTests
{
[Test]
public void OneLineSequenceProducesOneItem()
{
var sr = new StringReader("2015-01-19 [INFO] Message");
var cut = new LogEntryParser(sr);
Assert.That(cut.Parse().Count(), Is.EqualTo(1));
}
}
.NET Framework, XmlReader/
XmlWriter, XElement/XDocument . TextReader/TextWriter
,
, IReader/IWriter.

213

15


(Composite)
:
. .


, ,
. ,
.
,
.
- -, , .
: Severity , DateTime
. ,
.

15. (Composite)

DDD1 ,
(.15.1).
-,
.
LogImportRule . (SingleLogImportRule)
Func<LogEntry, bool>, . CompositeLogImportRule
. AndCo
mpositeLogImportRule OrCompositeLogImportRule,
.
ImportRuleFactory
( 15.1).
15.1.
public static class LogRuleFactory
{
public static LogImportRule Import(Func<LogEntry, bool> predicate)
{
return new SingleLogImportRule(predicate);
}
public static LogImportRule Or(this LogImportRule left,
Func<LogEntry, bool> predicate)
{
return new OrLogImportRule(left, Import(predicate));
}
public static LogImportRule And(this LogImportRule left,
Func<Log
Entry, bool> predicate)
{
return new AndLogImportRule(left, Import(predicate));
}

DDD (Domain-Driven Design) - , Domain-Driven Design:


Tackling Complexity in the Heart of Software, Prentice Hall, 2003: http://www.amazon.com/
Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215.

215

 

 

 


 
 


. 15.1. -

 


 
  








 
 


+ShouldImport(LogEntry): bool

 






 

 





CompositeLogImportRule

+ShouldImport(LofEntry): bool

LogImportRule

216
III.

15. (Composite)

public static LogImportRuleRejectOldEntriesWithLowSeverity(


TimeSpan period)
{
return
//
Import(le => le is ExceptionLogEntry)
//
.Or(le => (DateTime.Now le.EntryDateTime) > period)
.And(le =>le.Severity>= Severity.Warning)
//
.Or(le => (DateTime.Now le.EntryDateTime) <= period);
}
}
, Use, Or And, , .
RejectOldEntriesWithLowSeverity
, ,
.
, , ( 15.2).
15.2. -
var rule = ImportRuleFactory.RejectOldEntriesWithLowSeverity(
TimeSpan.FromDays(7));
LogEntry logEntry = new ExceptionLogEntry();
Assert.IsTrue(rule.ShouldImport(logEntry));
logEntry = new SimpleLogEntry(){ EntryDateTime = DateTime.Now.AddDays(-10) };
Assert.IsFalse(rule.ShouldImport(logEntry));
logEntry.Severity = Severity.Critical;
Assert.IsTrue(rule.ShouldImport(logEntry));
logEntry = new SimpleLogEntry()
{

217

218

III.

EntryDateTime = DateTime.Now.AddDays(-5),
Severity = Severity.Debug
};
Assert.IsTrue(rule.ShouldImport(logEntry));
,
, .
.15.2.

. 15.2.

:
Component (LogImportRule) . (ShouldImport), / ;
Composite (CompositeLogImportRule) ,
;
Leaf (SingleLogImportRule) ,
;
Client , .


. , -

15. (Composite)

Component: /
.
, . ,
,
Add/Remove Component.
, Leaf, ,
1.
,
.
.
.
,
Add/Remove .
Add/Remove .
, ,
/ CompositeComponent.
CompositeComponent,
Component
.
Add/Remove .
, , Add/Remove .
Leaf InvalidOpera
tionException ,
Add .

, . , ,
.
1

IV.

219

220

III.


, .
,
.

.NET Framework
, . .
System.Win
dows.Forms.Control WindowsForms, FrameworkElement WPF,
CompositeControl ASP.NET.
Xml XmlNode XElement.
Expression.

16


(Proxy)
:
.

.
, ,
.
, . .
-
,
.
, WCF, ASP.NET WebAPI
.NET Remoting, .

222

III.

WCF ILogSaver , ,
(ServiceContract + OperationContract Data
Contract + DataMember). ,
(binding), (contracts)
(endpoint). - ( -) , ILogSaver
1 ( 16.1).
16.1. - WCF
class LogSaverClient : ClientBase<ILogSaver>, ILogSaver
{
public void SaveLogEntry(LogEntrylogEntry)
{
// Channel
// ILogSaver
Channel.SaveLogEntry(logEntry);
}
}
//...
publicvoidSaveLogEntryAtTheBackend(LogEntrylogEntry)
{
var proxy = newLogSaverClient();
proxy.SaveLogEntry(logEntry);
proxy.Close();
}
ClientBase<T> WCF, ,
. LogSaverClient , WCF- ,
ILogSaver .
1

, , . ,
.

16. (Proxy)

.16.1.

. 16.1.

:
Client , ,
;
Subject (ILogSaver) ;
Proxy (LogSaverClient) -, , ;
RealSubject ,
.


,
.

.

.

, .
, .
,
. -

223

224

III.


. - 15
.


, - ,
. 1990- 2000-,

.
, DCOM .NETRemoting.
,

. , , ,
1. , WCF ASP.NETWebAPI, - . ISomeInter
face, ,
.
, ChannelBase<T> WCF,
, , -!

vs.
.
.
.
1

, . ILogSaver
. .
ILogSaver .

16. (Proxy)

,
. -
, ,
.

Lazy<T>
Lazy<T> ,
- ( 16.2).
16.2. Lazy<T>
public interface IHeavyweight
{
void Foo();
}
//
public class Heavyweight : IHeavyweight
{
public void Foo()
{}
}
// ,
//
public class HeavyweightProxy : IHeavyweight
{
private readonly Lazy<Heavyweight> _lazy = new Lazy<Heavyweight>();
public void Foo()
{
_lazy.Value.Foo();
}
}

225

226

III.

- ,
: ,
.

.NET Framework
-. .NET
Framework -: ChannelBase<T> WCF,
RealProxy .NETRemoting.
- ORM-. ORM
(Object-RelationalMapping - ),
NHibernate EntityFramework,
-. ORM (dataentities),
SQL- .

IV

17.

18. /

19.

20.

21.

22.

228

IV.

. , ,
. (
?),
. ,
,
,
.
,
SOLID. 1990-
C++ Report .
, , - .

SOLID.
Agile Software Development, Principles, Patterns, and Practices,
C# , C#.
(SOLID) ,
.
20 , , ++. ,
,
++ .
-
. , SOLID-

,
C# Java.
SOLID- ,
, ( )
,
.

IV.

(SRP The Single Responsibility Principle):


/ .
,
(tackling the complexity).
, . , .
, . , , .
/ (OCP The Open-Closed Principle):
(, , ..) , . () ,
. .
. ,
,
.
(LSP The Liskov Substitution Principle):
.
- , .
, , ,
.
(ISP The Interface Segregation Principle):
, .
, . ,
, .
, , -,
, .

229

230

IV.

(DIP The Dependency Inversion Principle):


.
.
. ,
, . .
, .

, .

17

.

(Single-Responsibility Principle, SRP): ( . , . 2006).
.
, ,
. - , ,
.
,
.
, . ,
,
.
. ()
, ,

232

IV.

. , .
: (, , )
, . ? . , , .
-
(essential complexity)
(accidental complexity).
. , .
, , ,
- - , ,
- .
. , -
.
: , -
, Windows-
-. SRP : Windows
Forms-, WCF-, Windows-, . , SRP
, , .
SRP,
. ,
, ,
. ,
, ,
.

17.

SRP
.
200, . 57
. , .
.
. , , ,
.
,
.
- ,
. ,
, .
SRP ,
. ,
, ?
? ?
SRP ,
. SRP,
40 .
SRP,
. SRP,
, .

. , ,
. ,

233

234

IV.

. ,
, , ,
, .
- .
- Elasticsearch .
.
, (17.1).
17.1. -
public class LogImporter
{
public void ImportLogs()
{
string[] logFileNames = GetListOfFilesFromAppConfig();
foreach (var file in logFileNames)
{
var logEntries = ReadLogEntries(file);
SaveLogEntries(logEntries);
}
}
private string[] GetListOfFilesFromAppConfig()
{
//
}
private IEnumerable<string> ReadLogEntries(string fileName)
{
//
}
private void SaveLogEntries(IEnumerable<string> entries)
{

17.

foreach (var entry in entries)


{
DateTime dateTime = ParseEntryTime(entry);
//
LogSaver.SaveEntry(dateTime, entry);
}
}
private DateTime ParseEntryTime(string entry)
{
// -,
}
}
LogImporter -.

,
LogSaver.
? . -
, . ,
,
(severity) .
,
. .
1. . , ,
, .
. , - ( 17.2).
17.2. LogImporter
public class LogImporter
{
private readonly ICollection<string> _logFileNames;

235

236

IV.

public LogImporter(ICollection<string> logFileNames)


{
_logFileNames = logFileNames;
}
public void ImportLogs()
{
foreach (var file in _logFileNames)
{
var logEntries = ReadLogEntries(file);
SaveLogEntries(logEntries);
}
}
//
}
, .

LogImporter. . , ,
,
, .

,
. ILogFileListProvider
.
,
LogImporter .
,
!

2. -.
, .
LogImporter ?
! : /

17.

, , .. -
. LogEntryParser ( 17.3).
17.3. LogEntryParser
Class LogEntryParser
{
public bool TryParse(string line, out LogEntry logEntry)
{
// .
// true, .
// false,
//
//
}
}
public class LogImporter
{
private readonly LogEntryParser _parser = new LogEntryParser();
public void ImportLogs()
{
foreach (varfilein _logFileNames)
{
IEnumerable<LogEntry>logEntries = ReadLogEntries(file);
SaveLogEntries(logEntries);
}
}
private IEnumerable<LogEntry> ReadLogEntries(string fileName)
{
//
using (var file = File.OpenText(fileName))
{

237

238

IV.

string line = null;


while ((line = file.ReadLine()) != null)
{
LogEntrylogEntry;
if (_parser.TryParse(line, outlogEntry))
{
yield return logEntry;
}
}
}
}
//
}
LogEntryParser .

LogImporter ,
.

3. . ,
-.
, . ,
-, .
LogEntryParser
( 17.4).
17.4. - LogEntryParser
[TestFixture]
public class LogEntryParserTests
{
[TestCase("2014-01-12 [DEBUG] message", Result = Severity.Debug)]

17.

[TestCase("[Info] Message", Result = Severity.Info)]


public Severity ParseSeverity(string line)
{
// Arrange
var parser = new LogEntryParser();
// Act & Assert
return parser.Parse(line).Severity;
}
}
static class LogEntryParserEx
{
line)

public static LogEntry Parse(this LogEntryParser parser, string

{
LogEntry logEntry;
parser.TryParse(line, out logEntry);
return logEntry;
}
}
LogEntryParser
. NUnit1 , -
.

Parse LogEntryParser.
, . LogEntry
Parser ,
.

.
1

-: http://bit.ly/ParametrizedUnitTests.

239

240

IV.

. LogImporter : -. ,
-
(17.5).
17.5. LogImporter
[TestFixture]
public class LogImporterIntegrationTests
{
[Test]
public void ImportFileWithTenEntries()
{
string fileName = "10Entry.log";
// Cleanup
TryRemoveExistingEntries(fileName);
// Arrange
var importer = new LogImporter(new[] {fileName});
// Act
importer.ImportLogs();
// Assert
Assert.That(GetEntriesCountForLogFile(fileName), Is.EqualTo(10));
}

. : , ,
(Arrange, Act, Assert, AAA) .
- ,
.
, : LogImporter (.17.1).

17.











  


 






 
 


. 17.1. LogImporter

, ,
.
.
LogImporter :
- .
, . ,
.

SRP
SRP :
. - , , WCF Windows-.
-,
;
(lowcohesion). //
. ,
, ;
. / , (
). //
;

241

242

IV.

. /
. ,
, . .

,
.
, . , ,
.
.

. , ,
.

18

/
;

.
. 1
/ (Open-Closed Principle, OCP):
(, , ..) ,
( . ,
. 2006).
. ,
.
, ,
, .

. ,
1

. ! . .: , 2006.

244

IV.

, .
, .
.
, .


/ SOLID-. , . , ,
1, .
/
- 1988 2, .
: (, ,
..) , . , .
. ,
. , , . , .
.
.
, , DLL EXE-,
.
1

.NET- Fabulousa
dventuresincoding,
stackoverflow.com .

- (-, 2005).

18. /

, /
(pluggable architecture) .
,
. An Open and Closed
Case1 , ( /
1996 43).
, ,
, .
:
, . .
, . ,

.
,
. , (
) . ,
,
( ).
/?
, : ,
, . , ,
. ,
. .. , , ,
:
, .
1

An Open and Closed Case by Uncle Bob (http://blog.8thlight.com/uncle-bob/2013/03/08/


AnOpenAndClosedCase.html).

245

246

IV.

, , , .
?
, ,
, . - , .

( ) , , ( ').

. 18.1.

,
. - 12 ,
:
, , , , .

18. /

, :
/,
, . - , ,
1.


/
OCP: .
, , ( , ),
. ,
. .
?
-, . ()

, ,
. ,
. String
, IString.
(information hiding) , /. (
implementation hiding)
,
( . 2004).
, . :
. , .
.
1

: !

247

248

IV.

: , ; ,
.
-, .
. ,
.

/

/
-.
:
-;
,
- .
,
.
pull-1 LogImporter.
push- ,
.
, LogImporter
.
LogFileReader, -
. - .
1

pull- push- 5, .

18. /

,
. C# .
IObservable<string>1, push-
( 18.1).
18.1. LogFileReader
public class LogFileReader : IObservable<string>
{
private readonly string _fileName;
public LogFileReader(string fileName)
{
_fileName = fileName;
}
public virtual IDisposable Subscribe(IObserver<string> observer)
{
using (var file = File.OpenText(_fileName))
{
string line = null;
while ((line = file.ReadLine()) != null)
{
observer.OnNext(line);
}
}
observer.OnCompleted(); return Disposable.Empty;
}
}

IObservable<T>
5.

249

250

IV.

LogFileReader ,
LogImporter
( 18.2).
18.2. LogImporter1 IObservable<string>
public class LogImporter
{
private readonly IObservable<string> _logFileReader;
private readonly LogEntryParser _parser = new LogEntryParser();
public LogImporter(string logFile)
{
_logFileReader = new LogFileReader(logFile);
}
public void ImportLogs()
{
_logFileReader.Subscribe(ProcessString);
}
private void ProcessString(string line)
{
LogEntry logEntry;
if (_parser.TryParse(line, out logEntry))
{
LogSaver.SaveEntry(logEntry);
}
}
}
LogImporter
_logFileReader. (Reactive Extensions, Rx)
IObserver<T>,
1

17 LogImporter - .
LogImporter .

18. /


LINQ-. push- , ProcessString,
, IObservable<T>1.
LogImporter
IObservable<string> .
. ,
.
LogFileReader
, (.18.2).

FileSystemWatcher2.

. 18.2. -


, /
, .
1

Reactive Extensions
- Introduction to Rx
introrx.com.

FilSystemWatcher
.

251

252

IV.

-
. LogEntryParser,
LogImporter.
, , . ,
.
,
. , ,
. -, .
LogEntryParser ,

, . LogImporter
( 18.3).
18.3. LogEntryParser
public class LogImporter
{
//
// private readonly LogEntryParser _parser
//

= new LogEntryParser();

private readonly LogEntryParser _parser;


public LogImporter(string logFile)
{
//
//
_parser = LogEntryParser.Create(logFile);
}

- . LogEntryParser,
.
(BackendLogEntry
Parser) (PostgreLogEntryParser)
(.18.3).

18. /

. 18.3. LogEntryParser


. (supple)
, .
.


/ -
. LogEntryPar
ser.Create , /.
(, )
BackendLogEntryParser PostgreLogEntryParser
(18.4).
18.4. LogEntryParser.Create
public abstract class LogEntryParser
{
public static LogEntryParser Create(string fileName)
{
if (fileName.StartsWith("Server"))
{
return new BackendLogEntryParser(fileName);
}
if (fileName.StartsWith("Postgre"))
{

253

254

IV.

return new PostgreLogEntryParser(fileName);


}
throw new InvalidOperationException(" ");
}
// ...
}
/?
: , , ,
.
,
. .
: , ,
.
, /, .

(as is),
/.
,
.

: -

/ -
(18.5).

18. /

18.5. DrawShape
public static void DrawShape(Shape shape)
{
switch(shape.ShapeType)
{
case ShapeType.Circle:
DrawCircle((Circle)shape);
break;
case ShapeType.Square:
DrawSquare((Square)shape);
break;
case ShapeType.Rectangle:
DrawRectangle((Rectangle)shape);
break;
default:
throw new InvalidOperationException(" ");
}
}
,
. - , Draw (18.5).
18.6. - DrawShape
public static void DrawShape(Shape shape)
{
shape.Draw();
}
, switch Draw
Shape . /, !
, , ,
, GetArea?

255

256

IV.

Shape
(breaking change) .
, ,

.
-
,
.
.
Shape Accept, IShapeVisitor,
Visit (18.7).
18.7.
public interface IShapeVisitor
{
void Visit(Circle circle);
void Visit(Square square);
void Visit(Rectangle rectangle);
}
public abstract class Shape
{
public abstract void Accept(IShapeVisitor visitor);
}
public class Circle : Shape
{
public override void Accept(IShapeVisitor visitor)
{
visitor.Visit(this);
}
}
GetArea IShapeVisitor ShapeEx (
18.8).

18. /

18.8.
public class ComputeAreaVisitor : IShapeVisitor
{
public double Area { get; private set; }
public void Visit(Circle circle)
{
Area = Math.PI * Math.Sqrt(circle.Radius);
}
public void Visit(Square square)
{
Area = Math.Sqrt(square.X);
}
public void Visit(Rectangle rectangle)
{
Area = rectangle.X * rectangle.Y;
}
}
public static class ShapeEx
{
public static double GetArea(this Shape shape)
{
var visitor = new ComputeAreaVisitor();
shape.Accept(visitor);
return visitor.Area;
}
}
// -
Shape shape = GetShape();
var area = shape.GetArea();

257

258

IV.

. ,
,
. ,
, 1.

.
.
.
,
.


/
/ .
. , , .
. (downcasting), .
.

OCP? /
/.
OCP:
.
OCP? , , , , .
1

,
, 6.

18. /

.
, .

Expression Problem1.
,
. ,
.

, (discriminate dunions)
.

: http://c2.com/cgi/
wiki?ExpressionProblem.

259

19

, .
, ?

(Liskov Substitution Principle, LSP):
( .
, . 2006).
... o1 S o2 T ,
P, T, P
o2 o1, S (subtype) T ( .
. 1988).
.
/ .
, .
-

19.

, ( 1). , .
1. ?
2. ?
(IS-A Relationship)
. , ,
, . (Subtype Inheritance),
. 12 (!) , ( ), IS-A, Can-Do ( ) ..
-
,
.
,
, .
,
. ,
,
.
c2.com2: .
, ,
.
1

(friendship relationship) ++ .
C# .
. .

Wiki,
. Liskov
Substitution Principle (http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple).

261

262

IV.

, , ,
.

- (Streams), (Enumerables),
, ..
, ,
: null,
,
( ), .
: ,
,
. , , ,
, ,
.
( )
, ,
.
?
:
. ,
-
;
- 1.

(http://c2.com/cgi/wiki?LiskovSubstitu
tionPrinciple).

19.

:

.
, . ,
, , ,
, , ,
?
, ,
. ( ) .
.
,
Rectangle Square (.19.1)?

. 19.1. ?

, ,
.
(): .
(): ,
.

263

264

IV.

, . ,
. , Width Height ! (
Width Height ,
,
.)
, .
,
! ,
(immutable), ,
. ,
!


C#. , IEnumerable<string> IEnumerable<object>.
, .

. -,
,
. -, - : , .
-, , ,
, (sealed)1
.
, /
,
.
, .
.

19.


,
, (.
- , 16.1).
,
. (
!), - ( , BCL?)
( !).
, ,
, , .

, ,
, , . , .
1. (
).
2. (
, ).
3. ( ).
4. , .
,
, .


,
. ,

265

266

IV.

InvalidOperationException NotSupportedException
, ,
. ,
.
, LSP , ImmutableList<T>
ReadOnlyCollection<T> IList<T>, NotSupportedException.
, .
IList<T> (, ICollection<T>) , Add
:
IsReadOnly False!
/, Read/Write , CanRead/CanWrite False.

. , ICollection<T>, ICollectionContract<T>.


Add IList<T> ICollection<T>
, .
Add .
ICollection<T> , .
, Add
1. (sets)
, , Add HashSet<int>
.
,
, ,
! InvalidOp
erationException, ,
,
.
,
T S , S
T (T S). ,
- ? ,
, , S T?

19.

,

. , ! ,
, .
, -,
.
(subtype inheritance)
, .
( ),
( ),

. (private inheritance),
-
!

. Eiffel, ,
, .NET-
.
C# (explicit interface implementation)
: ,

( 19.1).
19.1.
var list = new List<int> { 42 }.AsReadOnly();
//list.Add(42); // !
((IList<int>)list).Add(42); //
IList<int>list2 = list; // , !
list2.Add(42); //
, C#
.
:
,
.

, Eiffel
, .

267

268

IV.

Socket, IDis
posable Dispose
Close ( 19.2).
19.2.
Socket s = CreateSocket();
s.Dispose(); // .NET 4.0
((IDisposable)s).Dispose(); // OK
s.Close(); // OK
Framework Design Guidelines1
Dispose Pattern Guidelines:

.

++ ,
C#. , ++
, .. , ++
( ),
. ++ :
( ),
( / ).
++ .


-
.
- , .
/ :
, , ,
, .
, - .
1

Abrams B., Cwalina K. Framework Design Guidelines, 2nd Ed. Addison-Wesley Profes
sional, 2008.

19.

- , ,
, . LINQ (Language Integrated
Query) . LINQ
, IEnumerable<T>. , ,
yieldreturn, XML-,
.
, Enumerable , Count(), ElementAt(),
Last() ., , Collection<T>,
List<T> ..
Enumerable.Count()
19.3.
19.3. Count
public static int Count<TSource>(this IEnumerable<TSource> source)
{
var collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count;
var collection = source as ICollection;
if (collection != null) return collection.Count;
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (e.MoveNext()) count++;
}
return count;
}
Count() (,

269

270

IV.

, ICollection).
, ICollection,
, ,
ICollection.
.NETFramework Count,
ICollection, Lookup<T> ( 19.4).
19.4. Count Lookup
var lookup = Enumerable.Range(1, 10000).ToLookup(x => x);
Console.WriteLine(lookup.Count); // (1)1
Console.WriteLine(lookup.Count()); // (n)
lookup.Count , .
lookup.Count() , , .
, :

.


- ( 19.5).
19.5. LogEntryParser
public abstract class LogEntryParser
{
public abstract bool TryParse(string line, out LogEntry logEntry);
}
1

- .
, . (1) ,
. O(n)
: .
(http://ru.wikipedia.org/wiki/_) .

19.

,
. true
false .
logEntry .
.
, null line. ,
.
. ,
, (19.6).
19.6. LogEntryParser
public class LogEntryParserException : Exception
{}
[ContractClass(typeof (LogEntryParserContract))]
public abstract class LogEntryParser
{
/// <summary>
///
/// <paramref name="logEntry"/>
/// </summary>
/// <exception cref="LogEntryParserException">
/// ,
/// .
/// </exception>
public abstract bool TryParse(string line, out LogEntry logEntry);
}
[ContractClassFor(typeof (LogEntryParser))]
abstract class LogEntryParserContract : LogEntryParser
{
public override bool TryParse(string line, out LogEntry logEntry)
{

271

272

IV.

Contract.Requires(line != null);
Contract.Ensures(!Contract.Result<bool>() ||
Contract.ValueAtReturn(out logEntry) != null,
" True, logEntry
null");
throw new NotImplementedException();
}
}
,
, , .
LogEntryParser .
, LogEntryParserException
. ,
() - ( 19.7).
19.7. TryParse
public class IncorrectLogEntryParser : LogEntryParser
{
public override bool TryParse(string line, out LogEntry logEntry)
{
if (LineIsIncorrect(line))
{
// ! LSP!
throw new FormatException("Can't parse the line!");
}
// ...
}
}
TryParse false null
line. Argument
NullException ContractException ( 19.8).
19.8. TryParse
public override bool TryParse(string line, out LogEntry logEntry)
{

19.

logEntry = null;
// , line == null!
// LSP!
if (string.IsNullOrEmpty(line))
return false;
// ...
}
TryParse true, logEntry ( 19.9).
19.9. TryParse
public override bool TryParse(string line, out LogEntry logEntry)
{
logEntry = null;
// logEntry null! LSP!
return true;
// ...
}
.
, , .

LSP
LSP .
,
: , , , .
,
.

,
,

273

274

IV.

.
: , . , .
, ,
:
, .
,
.
,
, :
/ .
,

-,
. , , .
.


Barbara Liskov and Jannette Wing. A Behavioural Notion of Subtyping (http://web.
cse.ohio-state.edu/~neelam/courses/788/lwb.pdf). ,
, ,
, .
c2.com http://c2.com/cgi/wiki?Li
skovSubstitutionPrinciple. , ,
.
Programming Stuff. (
http://bit.ly/DbCBasics).
. , , , , .

20

,
; ,
.

(Interface Segregation Principle, ISP):
, (.
, . 2006).

. ,
, -
. ,
, ,
, ,
.

.
. ,
.

276

IV.

, .

, . , ,
.
,
, .

. , , ,
. ,
, .
,
.
, .
, .
.
. ,
, .
.
.
,
. , :

20.

;
- ( );
( ,
, );
( , , ,
: , , ..).

,
. , . Dependency Injectionin .NET
(http://bit.ly/DependencyManagement).

: , .
. ,
. ( ),
( 20.1).
20.1.

public Result Process1(List<RequestArgs> input)


{
foreach(var ra in input)
{
// ...
}
}
public Result Process2(IEnumerable<RequestArgs> input)
{
foreach(var ra in input)
{
// ...
}
}

277

278

IV.

IEnumerable<T>,
, List<T>.
-, Stream, MemoryStream.
, Configuration (-), IConfi
gurationProvider, Read
Configuration.

. ,
IEnumerable<T>, ,
. ,
Count() , , . (implicit
coupling) ,
,
.

SRP vs. ISP



.
. ISP
( . 2006).
. ,
,
(not cohesive), ,
. .
, .
, .
, ,
, .
. .
, ,
.
, .

20.

, , . , , ,
?
, , CRUD-1.
ISP? ! , . ,

.
, 11
, ISP .
SRP ISP.
(cohesive)
, .
(coupling) , ,
.

. , ,
.
2
. ,
SqlServerLogSaver Elastic
searchLogSaver. -,
ILogSaver (.20.1).
1

CRUD (Create, Read, Update, Delete) , .

12.

279

280

IV.

. 20.1.

SqlServerLogSaver ElasticsearchLogSaver
: .
(explicit interface implementation), ( 20.2).
20.2. ILogSaver
public class SqlServerLogSaver : ILogSaver
{
public void Save(DateTime dt, string severity, string message) {...}
public void SaveException(DateTime dt, Exception e) {...}
// !
ILogSaver.Save(LogEntry logEntry)
{
var exception = logEntry as ExceptionLogEntry;
if (exceptiony != null)
{
SaveException(exception.EntryDateTime, exception.Exception);
}
else
{

20.

Save(logEntry.EntryDateTime, logEntry.Severity.ToString(),
logEntry.Message);
}
}
}

. ,
SqlServerLogSaver Save(LogEntry),
( 20.3).
20.3.
var saver = new SqlServerLogSaver();
LogEntry logEntry = GetLogEntry();
saver.Save(logEntry); //
ILogSaver logSaver = saver;
logSaver.Save(logEntry); // OK
. , , , .
, .
17, . LogEntryParser
TryParse, .
Parse,
( 20.4).
20.4.
//
var parser = new LogEntryParser();
LogEntry logEntry;
if (parser.TryParse(stringEntry, outlogEntry))
{

281

282

IV.

SaveEntry(logEntry);
}
//
//
varparser = newLogEntryParser();
varlogEntry = parser.Parse(sampleStringEntry);
Assert.That(logEntry.Severity, Is.EqualTo(Severity.Debug));

.
, .

ISP
ISP .
,
.
.
, :
..
, ,
.

. , ,
, . ,
,
.
.
, ,

20.

,
/.
, .
:
, -, .
, , .
, .
.

283

21

,
!

(Dependency Inversion Principle, DIP):
.
. .
( . , . 2006).

, (Dependency Injection). ,
, , .
, , -
.

21.

1.
, ( 21.1).
21.1. DIP
interface IFileReader
{
string ReadLine();
}
class LogEntryParser
{
public LogEntryParser(IFileReader fileReader)
{}
public IEnumerable<LogEntry> ParseLogEntries()
{}
}
class FileReader : IFileReader {...}
(loosely couplied) ,
LogEntryParser IFileReader
. ,
/.
, , .
( ),
. GOTO ,
1

, interface.
,
.

285

286

IV.

.
,
.
LogEntryParser
, . , List<T> IList
GrowingPolicy, , String
IInterningPolicy,
! , ,
.
,
.
, ,
.

, ,
.

,
. , ( . 2006)
(.21.1).
. , , .
, , - .
.
,
, .

21.

















  









. 21.1.

, . , - (core business logic). , ,


.
, .

,
.

287

288

IV.


, , , ,
( . - . 2010).
.
LogImporter (.21.2). LogImporter LogEntryParser , . , .
, 1.

. 21.2. LogImporter

, . -
- .
, .
-, .


2. 1

1,
10.

5.

21.

,
.
, ,
, .

MVC (Model View Controller,
) (.21.3). : -,
,
.

. 21.3. 1

,
. , ? ,
UML , . ,
.
.

289

290

IV.

- .
,
. , ,
. MVC , , . , -,
, WPF
Windows Forms.
, MVP
(Model View Presenter, ) (.21.4).

. 21.4.

MVP MVC , , ,
. (IView),

21.

(, ), .
,
MVx MVVM (Model View View Model, ). MVVM MVP, IView
, (Data Binding).


(.21.5).

. 21.5.

:
,
.
, .

(21.2).
21.2. DIP

// Reporter.dll
public interface IReportFormatter
{

291

292

IV.

string FormatReport(Report report);


}
public class Reporter
{
private readonly IReportFormatter _formatter;
public Reporter(IReportFormatter formatter)
{
_formatter = formatter;
}
public void SendReport(Report report)
{
var formattedReport = _formatter.FormatReport(report);
SendFormattedReport(formattedReport);
}
private void SendFormattedReport(string formattedReport)
{}
}
// Application.dll
class XlsFormatter : IReportFormatter
{
public string FormatReport(Report report)
{
// Excel
}
}
class Application
{
public void Run()
{

21.

var reporter = new Reporter(new XlsFormatter());


reporter.SendReport(GenerateReport());
}
}
Reporter IReport
Formatter, Application .
IReportFormatter , Reporter,
. , , Reporter
XlsFormatter .

DIP

,
.
IoC-1 , , .
, . : DIP
: . , ;
.
1

IoC- (Inversion of Control Containers)


.
, .
(Entry Point) .
,
.
Dependency Injectionin .NET.

293

294

IV.

,
.
, .
, ,
.
:
, , , , .
, .
, , , .
. ,
.
DIP
.
,
, , .


vs.
-. , ,
?
, , 1
100%- !
1

-, -,
test doubles. (mocks) (stubs)
, . , ( Moq) (mocks),
.
Programming Stuff: (bit.ly/StubsVsMocks).

21.

, ! ,
.
, . -
.
,
IPartitioningStrategy
.
,
, .
,
.
,
.
( DIP).
,
, ( /).
,
, .
,
, .
.
,
.


LogEntryParser IFileReader
( 21.3).
21.3. LogEntryParser
class LogEntryParser
{

295

296

IV.

private readonly IFileReader _fileReader;


public LogEntryParser(IFileReader fileReader)
{
_fileReader = fileReader;
}
public IEnumerable<LogEntry> ParseLogEntries()
{
// _fileReader
//
yield break;
}
}
, ?
SRP. ,
. LogEntry
- (, ),
. ,
.
ISP1. LogEntryParser
(System.String), Parse
.
DIP. LogEntryParser IFileReader, , . ,
/,
System.Stream. - ,
IFileReader IRawLogEntryStream.
IRawLogEntryStream ,
, - .
1

ISP. .
LogEntryParser ,
, , IFileReader.

21.

, .
LogEntryParser .
, ,
, LogEntryReader ( 21.4).
21.4. LogEntryReader
class LogEntryReader : IDisposable
{
private readonly Stream _stream;
private readonly LogEntryParser _parser;
public LogEntryReader(Stream stream, LogEntryParser parser)
{
_stream = stream;
_parser = parser;
}
public void Dispose()
{
_stream.Close();
}
public IEnumerable<LogEntry> Read()
{
using (var sr = new StreamReader(_stream))
{
string line = null;
while ((line = sr.ReadLine()) != null)
{
LogEntry logEntry;
if (_parser.TryParse(line, out logEntry))
{
yield return logEntry;
}
}
}
}

297

298

IV.

. LogEntryReader
,
LogEntryParser .
,
LogEntryReader (
21.5).
21.5. LogEntryReader.FromFile
public static LogEntryReader FromFile(string fileName)
{
var fs = new FileStream(fileName, FileMode.Open);
var parser = LogEntryParser.Create(fileName);
return new LogEntryReader(fs, parser);
}
-,
1. ,
.
ILogEntryReader?
. LogEntryReader LogImporter ( 21.6).
21.6. LogImporter
public class LogImporter : IDisposable
{
private readonly LogEntryReader _logEntryReader;
public LogImporter(string logFile)
{
_logEntryReader = LogEntryReader.FromFile(logFile);
}
1

LogEntryParser.Create 18. , , . .

21.

public void Dispose()


{
_logEntryReader.Dispose();
}
public void ImportLogs()
{
foreach (var logEntry in _logEntryReader.Read())
{
LogSaver.SaveEntry(logEntry);
}
}
}
LogImporter , LogEntryReader LogSaver . ,
. LogImporter , ILogEntryReader ILogEntrySaver
( 21.7).
21.7. ILogEntryReader ILogEntrySaver
public class LogImporter
{
private readonly ILogEntryReader _reader;
private readonly ILogEntrySaver _saver;
public LogImporter(ILogEntryReader reader, ILogEntrySaver saver)
{
_reader = reader;
_saver = saver;
}
public void ImportLogs()
{

299

300

IV.

foreach (var logEntry in _reader.Read())


{
_saver.SaveEntry(logEntry);
}
}
// !
}

, ILogEntry
Reader ILogEntrySaver . LogImporter
, 21.7, ! LogImporter, LogSaver Log
EntryReader .

.

-.
, IFile
Stream,
.

, .

. DIP , . ,
. , -

21.

.

, .

DI vs. DIP vs. IoC


, ,
(inversion) (dependency):
IoC Inversion of Control ( );
DI Dependency Injection ( );
DIP Dependency Inversion Principle ( ).
.
, , DI-, IoC-
. DI DIP,
.

Inversion of Control
(Inversion of Control, IoC) ,
.
, ,
.
: ,
.

. IoC,
, , IoC-, ,

(.21.6).

. 21.6.

Dependency Injection
(Dependency Injection, DI)
.

301

302

IV.

: (Constructor
Injection), (Method Injection) (Property Injection).

(21.8).
21.8.
class ReportProcessor
{
private readonly IReportSender _reportSender;
// Constuctor Injection:
public ReportProcessor(IReportSender reportSender)
{
_reportSender = reportSender;
Logger = LogManager.DefaultLogger;
}
// Method Injection:
public void SendReport(Report report, IReportFormatter formatter)
{
Logger.Info("Sending report...");
var formattedReport = formatter.Format(report);
_reportSender.SendReport(formattedReport);
Logger.Info("Report has been sent");
}
// Property Injection:
//
public ILogger Logger {get; set;}
}

. ,
( IReportSender
ReportProcessor). ,
, (IReportFormatter

21.

, ReportProcessor ).
(
), (
Logger ,
).
, DI- ,
, , ..
.
!

Dependency Inversion Principle


(Dependency Inversion Principle. DIP)
, ,
. ,
.
.
, , ,
( 21.9).
21.9. DIP DI
class ReportProcessor
{
private readonly ISocket _socket;
public ReportProcessor(ISocket socket)
{
_socket = socket;
}
public void SendReport(Report report, IStringBuilder stringBuilder)
{
stringBuilder.AppendFormat(CreateHeader(report));
stringBuilder.AppendFormat(CreateBody(report));
stringBuilder.AppendFormat(CreateFooter(report));
_socket.Connect();
_socket.Send(ConvertToByteArray(stringBuilder));
}
}

303

304

IV.

ReportProcessor
ISocket,
.
SendReport: IStringBuilder
, ,
. , .
(DI),
(DIP).
. (IoC)
,
. (DI)
,
. (DIP) ,
, .


DI-: Constructor Injection (http://bit.ly/CustructorInjection).
DI-: Method Injection (bit.ly/MethodInjection).
DI-: Property Injection (bit.ly/PropertyInjection).
DIP in the Wild (http://martinfowler.com/articles/dipInTheWild.html).
Inversion of Control Containers and the Dependency Injection pattern (http://mar
tinfowler.com/articles/injection.html).
, (http://bit.ly/FrameworkDependencies).

22

! ,
, , ,
.

- ,
?
? 1,
?
1

.
software design, . design , .
, design .
? ? ? ,
. , . , ,
. .

306

IV.


.
:
? , , .
, .

: , , . , , ,
,
.
, : , ,
, ,
. ,
, .
, , ,
.
,
(coupling) (cohesion)1. (low coupling) (high cohesion). ,

. , .
, .
, , .
, , .
1

, .
,
. , .

22.

Agile!: The Good, The Hype, and The Ugly1 , : , .


(falsifiable). , (platitude). ,
, . , .
, , . , , .


, .
,
,
: ,
! ,
.
, : ,
, -! ,
!
,
.
, ,
, , .
( )
,
.
1

Meyer B., Agile!: The Good, The Hype, and The Ugly. Springer, 2014.

307

308

IV.

, ,
, ,
.

.
, .
,
: ,
, , !
, -, ,
!

: , (Shu, Ha,
Ri https://en.wikipedia.org/wiki/Shuhari). , .
, , .
,
. , , http://en.wikipedia.org/
wiki/Dreyfus_model_of_skill_acquisition.

. , , .
(lowcohesion) ,
.
/
. ,
.
- . .
, ,
. -

22.

. -
, .
. , , .
.
, ,
, : , .
. ,
.
. .
, , .
, . :
, ?

. , ,
: ,
, . . ,
,
. , , .
,
(overengineering): ? , ?
(premature generalization)?
,
.

309

310

IV.



. . , ,
,
.
Anti-SRP .
, /.
Anti-OCP . ,
,
.
Anti-LCP .
, .
Anti-ISP .
, .
Anti-DIP , DI .
.
, , .


,
.
,
.

. ,
: , ,
.
.
(SRP),
(OCP).
, LSP. ,
(ISP), (DIP).
.
. ,
. ,
, .

,
.

312

/
.
, . ,
. / . .
,
.
,
.


.

, : .
, .

.
, , .



1. . . - . .:
, 1994. ,
. , , .
2. . . .: , 2003. , . (Head-First Design Patterns),
: ,
, .
3. . -
. .: -, 2005. , -
- ( ) .
, -
.
, , , ,

314

, ( ).
4. . UML 2.0 . 3- . .:
, 2004. - : .
5. . - . .: ,
2003. - , , ,
. , ,
.
6. . - . .: , 2003. DDD (Domain-Driven Design) Event Sourcing, CQRS enterprise- Domain DataAccess.
, , , .
. .
7. . , C#.
.: -, 2011. , . , ,
. ,
.
,
C# http://sergeyteplyakov.blogspot.ru/2013/12/aboutagile-principles-patterns-and.html.
8. Beck K. Test-Driven Development: By Example. 2002. ,
, TDD , . ,
, , .
9. Freeman S., Pryce N. Growing Object-Oriented Software Guided by Tests. 2009.
TDD .

,
. .
10. . . . .: , 1999. , . : ,
, .
, .
11. Osherove R. The Art of Unit Testing: with examples in C#. 2014.
, .
: , , DI-, DDD-, , .
-.
. xUnit Test Patterns:
Refactoring Test Code,
.NET.
12. . . .: , 2004.
.
, - .
13. Cwalina K., Abrams B. Framework Design Guidelines. 2009. ,
( )
. ,
,
. , , ,
, . , , ,
,
C#.
, .
14. Seeman M. Dependency Injection in .NET, 2011. DI-.

315

316

. , Constructor Injection, Method Injection


., .
Must Read .NET-!
15. Petrisek T. Real-World Functional Programming: With Examples in F# and C#.
2010. ,
- . , C#, - F#.
16. . -,
. .: -, 1995.
, .
17. Brooks F. The Design of Design: Essays from a Computer Scientist. 2010.
.
.

(http://bit.ly/BestOODBooks).
C# .NET
C#/.NET (http://bit.ly/BestDotNetBooks).

200 , . , RSDN Magazine,


SoftwarePeople.Ru Habrahabr.ru.
, ,
. http://sergeyteplyakov.blog
spot.com/2013/10/articles.html.

.
.NET


.

.

.

.

. , .

.

, 192102, -, . (. ), 3, , . 7.
034-2014, 58.11.12
, .
25.03.15. 70100/16. . . . 25,800. 700. 0000.
. .
142300, , . , . , 1.
: www.chpk.ru. E-mail: marketing@chpk.ru
: 8(496) 726-54-10, : (495) 988-63-87


:
: www.piter.com
: postbook@piter.com
: (812) 7037374
: 197198, , / 127,
ICQ: 413763617

:

.
.
,
.
. : . Web-money USD
E-Gold, MoneyMail, INOCard, RBK Money (RuPay), USD Bets, Mobile Wallet
.
, ,
.
.
.
e-mail.

:
, , , , , e mail;
, , , , , ,
, ;
, , .

Вам также может понравиться