forked from shangerxin/BookNotes
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathC# Guide Official document;Note=Erxin.txt
1301 lines (963 loc) · 49.2 KB
/
C# Guide Official document;Note=Erxin.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
C# Guide Official document;Note=Erxin
# C# Guide
- https://docs.microsoft.com/en-us/dotnet/csharp/
# C# Version history
## version 1.0
- much similar to java. part of its stated design goals for ECMA
http://feeldotneteasy.blogspot.com/2011/01/c-design-goals.html
## version 2.0
- release 2005
- generics
public class GenericList<T>
{
void Add(T input){}
}
+ class
+ interface
+ delegate
+ method
- difference between c++ templates and c# generics
+ c# generate performs at runtime
+ c# generics do not provide the same amount of flexibility as c++ templates. it is not possible to call arithmetic operators in a c# generic class although it is possible to call suer defined operators
+ c# does not allow non-type template parameters such as template C<int i>{}
+ c# does not support explicit specialization; that is a custom implementation of a template for a specific type
+ c# does not support support partial specialization, a custom implementation for a subset of the type arguments
+ c# does not allow type parameter to be used as the base class for the generic type
+ c# does not allow type parameters to have default types
+ in c# a generic type parameter cannot itself be a generic, although constructed types can be used as generics, c++ does allow template paramters
+ c++ allow code that might not be valid for all type parameters in the template, which is then checked for the specific type used as the type parameter. c# only language constructs allowed are those that can be deduced from the constraints
- generics and reflection, in c# 2.0 the Type class enable run-time information for genreic types. The System.Reflection.Emit namespace also contains new members that support generic
+ how to define generic type with Reflection Emit
https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/how-to-define-a-generic-type-with-reflection-emit
parts of System.Type member
IsGenericType, return true if type is generic
- Generics in the run time
+ Generics work somewhat differently for reference types. The first time a generic type is constructed with any reference type, the runtime creates a specialized generic type with object references substituted for the parameters in the MSIL. , every time that a constructed type is instantiated with a reference type as its parameter, regardless of what type it is, the runtime reuses the previously created specialized version of the generic type. This is possible because all references are the same size.
+ When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic type with the supplied parameter or parameters substituted in the appropriate locations in the MSIL
- generic in .net framework class library, System.Collections.Generic, which includes several ready-to-use generic collection classes and associated interfaces.
- partial classes
public partial class Employee
{
}
public partial class Employee
{
}
+ advantage
allow multiple programmer to work on it at the same time
working with automatically generated source, code can be added without having to recreate the source file
+ any partial declare sealed then whole type consider sealed
+ auto merged for partial type
XML comments
interfaces
generic-type parameter attributes
class attributes
members
+ restrictions
all definitions must be marked with partial
nested partial class are allowed
all partial type definitions meant to be parts of the same type must be defined in same assmebly
+ partial methods, A partial class or struct may contain a partial method. One part of the class contains the signature of the method. An optional implementation may be defined in the same part or another part.
* partial methods must return void
+ can have ref but not out parameter
+ are implicity private and cannot be virtual
+ cannot be extern
+ can have static and unsafe modifiers
+ can be generic
- anonymouse methods
+ version 2.0, C# before 2.0, the only way to declare a delegate was to use named methods
- nullable type
type? obj;
obj.HasValue to determine if the type has been assigned value
+ box null type
The two boxed objects are identical to those created by boxing non-nullable types. And, just like non-nullable boxed types, they can be unboxed into nullable types
bool? b2 = (bool?)bBoxed;
int? i2 = (int?)iBoxed;
+ ?? operator, is called the null-coalescing operator. It returns the left-hand operand if the operand ids not null otherwise it returns the right hand operand
// Set y to the value of x if x is NOT null; otherwise,
// if x = null, set y to -1.
int y = x ?? -1;
- iterators, An iterator method or get accessor performs a custom iteration over a collection. An iterator method uses the yield return statement to return each element one at a time
public static System.Collections.IEnumerable SomeNumbers()
{
yield return 3;
yield return 5;
yield return 8;
}
type of an iterator method or get accessor can be IEnumerable, IEnumerable<T>, IEnumerator, or IEnumerator<T>.
+ When you create an iterator for a class or struct, you don't have to implement the whole IEnumerator interface. When the compiler detects the iterator, it automatically generates the Current, MoveNext, and Dispose methods of the IEnumerator or IEnumerator<T> interface.
+ An iterator can occur as a method or get accessor. An iterator cannot occur in an event, instance constructor, static constructor, or static finalizer.
- Covariance and Contravariance
+ In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments
// Assignment compatibility.
string str = "test";
// An object of a more derived type is assigned to an object of a less derived type.
object obj = str;
// Covariance.
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
// Contravariance.
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Action<object> actObject = SetObject;
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Action<string> actString = actObject;
## Version 3.0
- Auto implemented properties
class Customer
{
// Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; protected set; }
}
- anonymouse type, to encapsulate a set of read-only properties into a single object without having to explicityly define a type first
var v = new { Amount = 108, Message = "Hello" };
+ You can create an array of anonymously typed elements by combining an implicitly typed local variable and an implicitly typed array, as shown in the following example.
var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};
+ anonymouse type could only be explicit cast to object
+ two instances of the same anonymous type are equal only if all their properties are equal.
- Query expression basics
+ A query is a set of instructions that describes what data to retrieve from a given data source
+ a query is distinct from the results that it produces
+ important. The application always sees the source data as an IEnumerable<T> or IQueryable<T> collection
IEnumerable<int> highScoresQuery =
from score in scores
where score > 80
orderby score descending
select score;
+ A query expression is a query expressed in query syntax. A query expression is a first-class language construct. It is just like any other expression and can be used in any context in which a C# expression is valid
+ Use the group clause to produce a sequence of groups organized by a key that you specify.
var queryCountryGroups =
from country in countries
group country by country.Name[0];
+ You can use the into keyword in a select or group clause to create a temporary identifier that stores a query. Do this when you must perform additional query operations on a query after a grouping or select operation
var percentileQuery =
from country in countries
let percentile = (int) country.Population / 10_000_000
group country by percentile into countryGroup
where countryGroup.Key >= 20
orderby countryGroup.Key
select countryGroup;
select ... into effectively isolates the whole of one query and lets you use it as the input to a new query. Personally I usually prefer to do this via two variables:
+ Use the join clause to associate and/or combine elements from one data source with elements from another data source based on an equality comparison between specified keys in each element. In LINQ, join operations are performed on sequences of objects whose elements are different types. After you have joined two sequences, you must use a select or group statement to specify which element to store in the output sequence.
var categoryQuery =
from cat in categories
join prod in products on cat equals prod.Category
select new { Category = cat, Name = prod.Name };
+ Use the let clause to store the result of an expression, such as a method call, in a new range variable.
string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" };
IEnumerable<string> queryFirstNames =
from name in names
let firstName = name.Split(' ')[0]
select firstName;
when you do want to keep the previous query context, let makes more sense
+ A query clause may itself contain a query expression, which is sometimes referred to as a subquery. Each subquery starts with its own from clause that does not necessarily point to the same data source in the first from clause.
var queryGroupMax =
from student in students
group student by student.GradeLevel into studentGroup
select new
{
Level = studentGroup.Key,
HighestScore =
(from student2 in studentGroup
select student2.Scores.Average())
.Max()
};
- lambda expression
(x)=>{...}
- expression trees
+ An expression tree provides a method of translating executable code into data
+ it is useful for transform C# code such as a LINQ query expression into code that operates on another process, such as a SQL database.
+ LINQ provides a simple syntax for translating code into a data structure called an expression tree. The first step is to add a using statement to introduce the Linq.Expressions namespace:
Expression<Func<int, int, int>> expression = (a,b) => a + b;
VS2008 contain a tool ExpressionTreeVisualizer. It can be used to visualize an expression tree.
BinaryExpression body = (BinaryExpression)expression.Body;
ParameterExpression left = (ParameterExpression)body.Left;
ParameterExpression right = (ParameterExpression)body.Right;
+ compiling an expression back into code
int result = expression.Compile()(3, 5);
Console.WriteLine(result);
+ the variable query that is returned by this LINQ expression is of type IQueryable. Here is the declaration of IQueryable:
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryProvider Provider { get; }
}
+ A LINQ to SQL query is not executed inside your C# program. Instead, it is translated into SQL, sent across a wire, and executed on a database server. In other words, the following code is never actually executed inside your program
It is obviously going to be much easier to translate a data structure such as an expression tree into SQL than it is to translate raw IL or executable code into SQL
+ IQueryable<T> and IEnumerable<T>, linq to object return IEnumerable<T> and linq to sql return IQueryable
If code can be executed in process then the job can be done with the simple type called IEnumerable<T>
If you need to translate a query expression into a string that will be passed to another process, then use IQueryable<T> and expression trees.
+ Projects like LINQ to Amazon that need to translate query expressions into web service calls that execute out of process will typically make use of IQueryable<T> and expression trees
- extension methods
class MyClass
{...}
static class ExtendMyClass
{
public static double Average(this MyClass obj)
{}
}
the extension method must by public and static
## Version 4.0
- dynamic binding
+ dynamic type enables the operations in which it occurs to bypass compile-time type checking
+ The dynamic type simplifies access to COM APIs such as the Office Automation APIs, and also to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM).
+ As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time.
+ context
+ ExandoObject Represents an object whose members can be dynamically added and removed at run time.
- named/optional argument
void foo(a=3,b=5)
{
}
+ named argument. If you do not remember the order of the parameters but you do know their names, you can send the arguments in either order, weight first or height first.
CalculateBMI(weight:123, heigyht:64);
+ You can also declare optional parameters by using the .NET OptionalAttribute class. The OptionalAttribute do not requied default value. Indicates that a parameter is optional.
+ COM Interface. The AutoFormat method in the Microsoft office excel range interface
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );
+ Overload resolution
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly specified.
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call.
- generic convariant and contravariant, the ability to use a less derived (less specific) or more derived type (more specific) than originally specified. Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types.
+ Covariance, Enables you to use a more derived type than originally specified.
assign an instance of IEnumerable<Derived> (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable<Base>.
+ Contravariance, You can assign an instance of IEnumerable<Base> (IEnumerable(Of Base) in Visual Basic) to a variable of type IEnumerable<Derived>
+ Invariance, could only assign the right generic type
+ Covariance and contravariance are collectively referred to as variance. A generic type parameter that is not marked covariant or contravariant is referred to as invariant
+ delegates can combine only if their types match exactly.
using System;
public class Type1 {}
public class Type2 : Type1 {}
public class Type3 : Type2 {}
public class Program
{
public static Type3 MyMethod(Type1 t)
{
return t as Type3 ?? new Type3();
}
static void Main()
{
Func<Type2, Type2> f1 = MyMethod;
// Covariant return type and contravariant parameter type.
Func<Type3, Type1> f2 = f1;
Type1 t1 = f2(new Type3());
}
}
+ enable you to mark the generic type parameters of interfaces and delegates as covariant or contravariant. A covariant type parameter is marked with the out keyword, A contravariant type parameter is marked with the in keyword
+ variance in delegates
public class First { }
public class Second : First { }
public delegate First SampleDelegate(Second a);
public delegate R SampleGenericDelegate<A, R>(A a);
// Matching signature.
public static First ASecondRFirst(Second first)
{ return new First(); }
// The return type is more derived.
public static Second ASecondRSecond(Second second)
{ return new Second(); }
// The argument type is less derived.
public static First AFirstRFirst(First first)
{ return new First(); }
// The return type is more derived
// and the argument type is less derived.
public static Second AFirstRSecond(First first)
{ return new Second(); }
// Assigning a method with a matching signature
// to a non-generic delegate. No conversion is necessary.
SampleDelegate dNonGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a non-generic delegate.
// The implicit conversion is used.
SampleDelegate dNonGenericConversion = AFirstRSecond;
// Assigning a method with a matching signature to a generic delegate.
// No conversion is necessary.
SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a generic delegate.
// The implicit conversion is used.
SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;
+ in .net 4.0 or later. To enable implicit conversion, you must explicitly declare generic parameters in a delegate as covariant or contravariant by using the in or out keyword.
// Type T is declared covariant by using the out keyword.
public delegate T SampleGenericDelegate <out T>();
public static void Test()
{
SampleGenericDelegate <String> dString = () => " ";
// You can assign delegates to each other,
// because the type T is declared covariant.
SampleGenericDelegate <Object> dObject = dString;
}
* In the following code example, SampleGenericDelegate<String> cannot be explicitly converted to SampleGenericDelegate<Object>, although String inherits Object. You can fix this problem by marking the generic parameter T with the out keyword.
public delegate T SampleGenericDelegate<T>();
public static void Test()
{
SampleGenericDelegate<String> dString = () => " ";
// You can assign the dObject delegate
// to the same lambda expression as dString delegate
// because of the variance support for
// matching method signatures with delegate types.
SampleGenericDelegate<Object> dObject = () => " ";
// The following statement generates a compiler error
// because the generic type T is not marked as covariant.
// SampleGenericDelegate <Object> dObject = dString;
}
* .net 4.0 built-in delegates
Action delegates from the System namespace, for example, Action<T> and Action<T1,T2>
Func delegates from the System namespace, for example, Func<TResult> and Func<T,TResult>
The Predicate<T> delegate
The Comparison<T> delegate
The Converter<TInput,TOutput> delegate
* declaring variant type parameters in generic delegates
out keyword. The covariant type can be used only as a method return type and not as a type of method arguments.
public delegate R DCovariant<out R>();
declare a generic type parameter contravariant in a generic delegate by using the in keyword. The contravariant type can be used only as a type of method arguments and not as a method return type
public delegate void DContravariant<in A>(A a);
It is also possible to support both variance and covariance in the same delegate, but for different type parameters. This is shown in the following example.
* ref and out parameters in C# can't be marked as variant.
* Variance for generic type parameters is supported for reference types only. For example, DVariant<int> can't be implicitly converted to DVariant<Object> or DVariant<long>, because integer is a value type
- embedded interop types, In Visual Studio, when adding one reference to the project, the properties window has an option Embed Inteop Types, should we set it to True or False? What's the difference?
This option was introduced in order to remove the need to deploy very large PIAs (Primary Interop Assemblies) for interop.
It simply embeds the managed bridging code used that allows you to talk to unmanaged assemblies, but instead of embedding it all it only creates the stuff you actually use in code
https://stackoverflow.com/questions/20514240/whats-the-difference-setting-embed-interop-types-true-and-false-in-visual-studi
Embedded interop types alleviated a deployment pain.
http://blogs.clariusconsulting.net/kzu/check-your-embed-interop-types-flag-when-doing-visual-studio-extensibility-work/
http://blogs.msdn.com/b/samng/archive/2010/01/24/the-pain-of-deploying-primary-interop-assemblies.aspx
## Version 5.0
- Asynchronous methods
+ task based asynchronous pattern
https://msdn.microsoft.com/library/hh873175.aspx
The core of async programming are the Task and Task<T> objects, which model asynchronous operations. They are supported by the async and await keywords.
+ i/o bound example, downloading data from a website
private readonly HttpClient _httpClient = new HttpClient();
downloadButton.Clicked += async (o, e) =>
{
// This line will yield control to the UI as the request
// from the web service is happening.
//
// The UI thread is now free to perform other work.
var stringData = await _httpClient.GetStringAsync(URL);
DoSomethingWithData(stringData);
};
+ cpu-bound example, The best way to handle this is to start a background thread which does the work using Task.Run, and await its result
private DamageResult CalculateDamageDone()
{
// Code omitted:
//
// Does an expensive calculation and returns
// the result of that calculation.
}
calculateButton.Clicked += async (o, e) =>
{
// This line will yield control to the UI while CalculateDamageDone()
// performs its work. The UI thread is free to perform other work.
var damageResult = await Task.Run(() => CalculateDamageDone());
DisplayDamage(damageResult);
};
+ async in depth, https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth
promise model of asynchrony, https://en.wikipedia.org/wiki/Futures_and_promises
+ Waiting for Multiple Tasks to Complete, The Task API contains two methods, Task.WhenAll and Task.WhenAny
public async Task<User> GetUser(int userId)
{
// Code omitted:
//
// Given a user Id {userId}, retrieves a User object corresponding
// to the entry in the database with {userId} as its Id.
}
public static Task<IEnumerable<User>> GetUsers(IEnumerable<int> userIds)
{
var getUserTasks = new List<Task<User>>();
foreach (int userId in userIds)
{
getUserTasks.Add(GetUser(id));
}
return await Task.WhenAll(getUserTasks);
}
+ important info and advice
* async methods need to have an await keyword in their body or they will never yield!
* You should add "Async" as the suffix of every async method name you write
* async void should only be used for event handlers because event handlers do not have return types. The caller have to know the method is run as async
* Exceptions thrown in an async void method can’t be caught outside of that method.
* Tread carefully when using async lambdas in LINQ expressions. Lambda expressions in LINQ use deferred execution, meaning code could end up executing at a time when you’re not expecting it to. The introduction of blocking tasks into this can easily result in a deadlock if not written correctly
* Write code that awaits Tasks in a non-blocking manner
Use this... Instead of this... When wishing to do this
await Task.Wait or Task.Result Retrieving the result of a background task
await Task.WhenAny Task.WaitAny Waiting for any task to complete
await Task.WhenAll Task.WaitAll Waiting for all tasks to complete
await Task.Delay Thread.Sleep Waiting for a period of time
* Write less stateful code
https://en.wikipedia.org/wiki/Referential_transparency_%28computer_science%29
+ task based asynchronous pattern, TAP
https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap
* TAP uses a single method to represent the initiation and completion of an asynchronous operation. This is in contrast to the Asynchronous Programming Model (APM or IAsyncResult) pattern, which requires Begin and End methods
* Event-based Asynchronous Pattern (EAP), which requires a method that has the Async suffix and also requires one or more events, event handler delegate types, and EventArg-derived types. Asynchronous methods in TAP include the Async suffix after the operation name; for example, GetAsync for a Get operation
* However, out and ref parameters are exempt from this rule and should be avoided entirely. Any data that would have been returned through an out or ref parameter should instead be returned as part of the TResult returned by Task<TResult>
* For all other errors, exceptions that occur when an asynchronous method is running should be assigned to the returned task, even if the asynchronous method happens to complete synchronously before the task is returned. Typically, a task contains at most one exception.
* Task class exposes a Start method. Tasks that are created by the public Task constructors are referred to as cold tasks, because they begin their life cycle in the non-scheduled Created state and are scheduled only when Start is called on these instances. TaskStatus.Created
the TAP method must call Start on the Task object before returning it. Consumers of a TAP method may safely assume that the returned task is active and should not try to call Start on any Task that is returned from a TAP method
* Cancellation, exposes an overload of the asynchronous method that accepts a cancellation token (CancellationToken instance).
public Task ReadAsync(byte [] buffer, int offset, int count,
CancellationToken cancellationToken);
If it receives a cancellation request, it may choose to honor that request and cancel the operation. If the cancellation request results in work being ended prematurely, the TAP method returns a task that ends in the Canceled state; there is no available result and no exception is thrown
Faulted and RanToCompletion states. Therefore, if a task is in the Canceled state, its IsCompleted property returns true. When a task completes in the Canceled state, any continuations registered with the task are scheduled or executed, unless a continuation option such as NotOnCanceled was specified to opt out of continuation
* In TAP, progress is handled through an IProgress<T> interface, which is passed to the asynchronous method as a parameter that is usually named progress. Providing the progress interface when the asynchronous method is called helps eliminate race conditions that result from incorrect usage
public Task ReadAsync(byte[] buffer, int offset, int count,
IProgress<long> progress);
* The .NET Framework 4.5 provides a single IProgress<T> implementation: Progress<T>. The Progress<T> class is declared as follows
public class Progress<T> : IProgress<T>
{
public Progress();
public Progress(Action<T> handler);
protected virtual void OnReport(T value);
public event EventHandler<T> ProgressChanged;
}
* If a TAP implementation uses both the optional CancellationToken and optional IProgress<T> parameters, it could potentially require up to four overloads
- Caller info attributes
+ reference, https://www.codeproject.com/Tips/606379/Caller-Info-Attributes-in-Csharp
I was going through the features of C#5.0 and one thing that I found interesting was CallerInfoAttributes. These attributes help in tracking information about the caller (method,property etc.) There are three types of attributes which are useful in doing so.
[CallerMemberName] - Sets the information about caller member name.
[CallerFilePath] - Sets the information about caller's source code file.
[CallerLineNumber] - Sets the information about caller's line number.
using System;
using System.Runtime.CompilerServices;
public class CallerInfoDemo
{
public static void Main()
{
ShowCallerInfo();
Console.ReadKey();
}
public static void ShowCallerInfo(
[CallerMemberName] string callerName = null,
[CallerFilePath] string callerFilePath = null,
[CallerLineNumber] int callerLine=-1)
{
Console.WriteLine("Caller Name: {0}", callerName);
Console.WriteLine("Caller FilePath: {0}", callerFilePath);
Console.WriteLine("Caller Line number: {0}", callerLine);
}
}
+ Another use of [CallerMemberName] is in simplifying INotifyPropertyChanged. This attribute is useful in logging the caller name as well as events notification which involve single property change
* INotifyPropertyChanged structure
public interface INotifyPropertyChanged
{
event PropertyChangedEventHandler PropertyChanged;
}
public delegate void PropertyChangedEventHandler (object sender, PropertyChangedEventArgs e);
public class PropertyChangedEventArgs : EventArgs
{
public PropertyChangedEventArgs (string propertyName);
public virtual string PropertyName { get; }
}
* class implement INotifyPropertyChanged
public class EmployeeVM:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
private string _phone;
public string Phone
{
get { return _phone; }
set
{
_phone = value;
OnPropertyChanged("Phone");
}
}
}
* utilized CallerMemberName attribute to implement the OnPropertyChanged
public class EmployeeVM:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName=null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
// The compiler converts the above line to:
// RaisePropertyChanged ("Name");
}
}
private string _phone;
public string Phone
{
get { return _phone; }
set
{
_phone = value;
OnPropertyChanged();
// The compiler converts the above line to:
// RaisePropertyChanged ("Phone");
}
}
}
## Version 6.0
- Static imports
+ using static Directive, The using static directive designates a type whose static members you can access without specifying a type name.
using static <fully-qualified-type-name>
+ .net compiler platform("Roslyn"), https://github.com/dotnet/roslyn
- Exception filters
+ They allow you to specify a condition on a catch block
static void Main()
{
try
{
Foo.DoSomethingThatMightFail(null);
}
catch (MyException ex) when (ex.Code == 42)
{
Console.WriteLine("Error 42 occurred");
}
}
//not equal with
static void Main()
{
try
{
Foo.DoSomethingThatMightFail(null);
}
catch (MyException ex)
{
if (ex.Code == 42)
Console.WriteLine("Error 42 occurred");
else
throw;
}
}
* There is actually a subtle but important difference: exception filters don’t unwind the stack. OK, but what does that mean?
* It’s interesting to note that an exception filter can contain any expression that returns a bool (well, almost… you can’t use await, for instance). It can be an inline condition, a property, a method call, etc. This allow us log exception on the fly without influence the stack
try
{
DoSomethingThatMightFail(s);
}
catch (Exception ex) when (Log(ex, "An error occurred"))
{
// this catch block will never be reached
}
- Property initializers
public class PepperoniPizza
{
public decimal ExtraPrice { get; set; } = 0.25m;
}
+ doesn't support none static initializer
+ support virtual property
public virtual decimal Price { get; set; } = 3.00m;
- Expression bodied members
+ getter-only properties/indexers with a body that can be represented as an expression
public string FormalName {
get { return FirstName[0] + ". " + LastName; }
}
+ now in c# 6.0 could be write as
public string GetFullName() => FirstName + " " + LastName;
public string FormalName => FirstName[0] + ". " + LastName;
public string FieldName => _getter.Name;
- Null propagator, the property initializer could introduce NullReferenceException when some of the property are Null. in c# 6.0 support null propagation operator(?)
var minPrice = product?.PriceBreaks?[0]?.Price;
//then we don't required to write
double minPrice = 0;
if (product != null
&& product.PriceBreaks != null
&& product.PriceBreaks[0] != null)
{
minPrice = product.PriceBreaks[0].Price;
}
+ for delegate we have to use
var result = myDelegate?.Invoke("someArgument");
- String interpolation, An interpolated string looks like a template string that contains interpolated expressions. An interpolated string returns a string that replaces the interpolated expressions that it contains with their string representations
Console.WriteLine($"Name = {name}, hours = {hours:hh}");
//equal to
Console.WriteLine("Name = {0}, hours = {1:hh}", name, hours);
+ syntax
$"<text> {<interpolated-expression> [,<field-width>] [:<format-string>] } <text> ..."
+ To include a curly brace ("{" or "}") in an interpolated string, use two curly braces, "{{" or "}}". See the Implicit Conversions section for more details
quotation mark ("), colon (:), or comma (,), they should be escaped if they occur in literal text, or they should be included in an expression delimited by parentheses
var s1 = $"He asked, \"Is your name {name}?\", but didn't wait for a reply.";
Console.WriteLine(s1);
+ Verbatim interpolated strings use the @ character followed by the $ character
var s1 = $@"He asked, ""Is your name {name}?"", but didn't wait for a reply.
{name} is {age:D3} year{(age == 1 ? "" : "s")} old.";
Console.WriteLine(s1);
+ FormattableString also includes ToString() overloads that let you produce result strings for the InvariantCulture and CurrentCulture
- Named operator, get nameof property
switch (e.PropertyName)
{
case nameof(SomeProperty):
{ break };
// opposed to
case "SomeOtherProperty":
{ break;}
}
- Dictionary initializer
+ init a dictionary
class StudentName
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
}
Dictionary<int, StudentName> students = new Dictionary<int, StudentName>()
{
{ 111, new StudentName {FirstName="Sachin", LastName="Karnik", ID=211}},
{ 112, new StudentName {FirstName="Dina", LastName="Salimzianova", ID=317}},
{ 113, new StudentName {FirstName="Andy", LastName="Ruth", ID=198}}
};
- await in catch and finally blocks
public static async Task<string> MakeRequestAndLogFailures()
{
await logMethodEntrance();
var client = new System.Net.Http.HttpClient();
var streamTask = client.GetStringAsync("https://localHost:10000");
try {
var responseText = await streamTask;
return responseText;
} catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
{
await logError("Recovered from redirect", e);
return "Site Moved";
}
finally
{
await logMethodExit();
client.Dispose();
}
}
- index initializers
private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today."
};
- Extension Add methods in collection initializers.
public class ClassList
{
public Enrollment CreateEnrollment()
{
var classList = new Enrollment()
{
new Student("Lessie", "Crosby"),
new Student("Vicki", "Petty"),
new Student("Ofelia", "Hobbs"),
new Student("Leah", "Kinney"),
new Student("Alton", "Stoker"),
new Student("Luella", "Ferrell"),
new Student("Marcy", "Riggs"),
new Student("Ida", "Bean"),
new Student("Ollie", "Cottle")
};
return classList;
}
}
public static class StudentExtensions
{
public static void Add(this Enrollment e, Student s) => e.Enroll(s);
}
After the collection contain an add method then it could be init in a easier way
- Improved overload resolution, in the previous version Task.Run(Action) and Task.Run(Func<task>) could not be distincted. Now Task.Run(Func<Task>()) is better
# Version 7.0
- Out variables, the out keyword was used to pass a method argument's reference. Before a variable is passed as an out argument, it must be declared and don't required to be initialized
class Program
{
static void Main(string[] args)
{
AuthorByOutParam(out string authorName, out string bookTitle, out long publishedYear);
Console.WriteLine("Author: {0}, Book: {1}, Year: {2}",
authorName, bookTitle, publishedYear);
Console.ReadKey();
}
static void AuthorByOutParam(out string name, out string title, out long year)
{
name = "Mahesh Chand";
title = "A Programmer's Guide to ADO.NET with C#";
year = 2001;
}
}
- Tuples and deconstruction
+ create tuple with
var letters = ("a", "b");
var alphabetStart = (Alpha: "a", Beta: "b");
+ deconstruct
var (count, sum) = Tally(values);
The Deconstruct method can also be an extension method, which can be useful if you want to deconstruct a type that you don’t own.
var tuple = Tuple.Create("foo", 42);
var (name, value) = tuple;
Console.WriteLine($"Name: {name}, Value = {value}");
- Pattern matching
+ Pattern matching supports is expressions and switch expressions.
foreach(var item in values)
{
if (item is int val)
sum += val;
else if (item is IEnumerable<object> subList)
sum += DiceSum2(subList);
}
+ The is pattern expression works quite well in this scenario,switch statement
switch (item)
{
case 0:
break;
case int val:
sum += val;
break;
case IEnumerable<object> subList when subList.Any():
sum += DiceSum4(subList);
break;
case IEnumerable<object> subList:
break;
case null:
break;
default:
throw new InvalidOperationException("unknown item type");
}
- Local functions, local functions enable you to declare methods inside the context of another method. This makes it easier for readers of the class to see that the local method is only called from the context in which is it declared.
public Task<string> PerformLongRunningWork(string address, int index, string name)
{
if (string.IsNullOrWhiteSpace(address))
throw new ArgumentException(message: "An address is required", paramName: nameof(address));
if (index < 0)
throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non-negative");
if (string.IsNullOrWhiteSpace(name))