This is the third and final part of my series of notes on learning C#.
- Essential C# 4.0: Basics
- Essential C# 4.0: Intermediate
- Essential C# 4.0: Advanced(this post)
In general, C# leaves me an unpleasant impression of redundancy and tyranny. The designers of the language seem to be always mocking “oh my stupid boy, we have to spare no effort to prevent you from making stupid mistakes~” However, this idea of design is good to some extend.
My passion on coding is mostly inspired by the colorful vim on Ubuntu. It is amazing fun. I love it!! So the first app I install on my new Windows workstation is, of course, cygwin. Now I have to use Visual Studio, so the first plugin I install on it is surely vsvim. Moreover, maybe I am not a guy of Eclipse. I can see no beauty and usability in it, although it is much more extensible than Visual Studio. The experience of configuring the build environment of Android and later Hadoop is awful and drives me crazy.
As to the last chapters of this book, I am not interested in muti-processing/multi-threading in Windows OS, which is much slower than *nix OS and thus somewhat boring. Windows was not designed to be a multiprocessing and multi-user platform in the first place; instead, it was originally intended for personal usage. So I just skimmed this chapter. Maybe I will revisit it someday when I have to exhaust the computing power on Windows. May that not happen.
At last, C# is not designed for manipulating pointers and addresses directly. Why do we bother to study it? We have C/C++ already. So I also just skimmed the last two chapters. :D
The following is my notes.
14 Collection Interfaces with Standard Query Operators 535
- Anonymous Types
var patent = new {Title = "Bifocals", YearOfPublication = "1784"}
- Implicit Typed Local Variables (
var
)- There is no difference in the resultant CIL code for implic- itly typed variables whose assignment is not an anonymous type (such as string) and those that are declared as type string.
- still strongly typed as well by the compiler.
- Language Contrast: JavaScript’s var is dynamically typed. See here. C# is (usually) a statically typed language.
- You should use implicitly typed variable declarations sparingly
- To accomplish this with implicitly typed local variables, use them only when the type assigned to the implicitly typed variable is entirely obvious and makes themselves more readable.
- e.g.
var items = new Dictionary<string, List<Account>>();
- e.g.
Dictionary<string, List<Account>> dictionary = GetAccounts();
- the requirements for two anonymous types to be type-compatible within the same assembly are a match in property names, data types, and order of properties.
- Collection Initializers
- Collections
- Arrays(length fixed, index operator supported)
foreach(TItem item in array) {}
- IEnumerable
(such as Stack<T>
,Queue<T>
,Dictionary<Tkey, Tvalue>
)while (stack.MoveNext()) {number = stack.Current; Console.WriteLine(number)}
- The state of moving to the next is shared. So we need
Enumerator
andGetEnumerator()
Dispose()
the enumerator’s state. A more simplified version in the example.
foreach
withoutIEnumerable
?- “duck typing”: if no IEnumerable/IEnumerable
method is found, it looks for the GetEnumerator()
method to return a type with Current() and MoveNext() methods. Duck typing involves searching for a method by name rather than relying on an interface or explicit method call to the method.
- “duck typing”: if no IEnumerable/IEnumerable
- compiler prevents assignment of the foreach variable Do not modify the collection during a foreach loop.
- Arrays(length fixed, index operator supported)
- Standard Query Operators
- Each method on
IEnumerable<T>
is a standard query operator - Filtering with
Where()
- A delegate expression that takes an argument and returns a Boolean is called a predicate
- Projecting with
Select()
IEnumerable<FileInfo> files = fileList.Select(file => new FileInfo(file))
- PLINQ(Parallel LINQ):
.AsParallel().
See CH18, CH19
- Counting with
Count()
- Deferring Execution: One of the most important concepts to remember when using LINQ
- At the time of declaration(“.Where()”), lambda expressions do not execute. It isn’t until the lambda expressions are invoked (
foreach
) that the code within them begins to execute. - To avoid such repeated execution, it is necessary to cache the data that the executed query retrieves. To do this, you assign the data to a local collection using one of the “To” method’s collection methods.
- At the time of declaration(“.Where()”), lambda expressions do not execute. It isn’t until the lambda expressions are invoked (
- Sorting with
OrderBy()
andOrderBy().ThenBy()
- return a
IOrderedEnumerable<T>
instead ofIEnumerable<T>
- return a
IEnumerable<IGrouping<int, Employee>> groupedEmployees = employees.GroupBy((employee) => employee.DepartmentId);
GroupJoin()
,SelectMany()
…
- Each method on
1 2 3 4 5 6 7 |
|
15 LINQ with Query Expressions 589
- More readable and SQL-like query expressions, when compared to Standard Query Operators
16 Building Custom Collections 611
- More Collection Interfaces
IList<T>
IDictionary<TKey, TValue>
IComparable<T>
ICollection<T>
- Primary Collection Classes
List<T>
Dictionary<TKey, TValue>
SortedDictionary<TKey, TValue>
andSortedList<T>
Stack<T>
Queue<T>
LinkedList<T>
- Providing an Index Operator
[]
public T1 this[T2 index] {}
andpublic T this[params PairItem[] branches] {}
- Returning null or an Empty Collection
- The better choice in general is to return a collection instance with no items.
- One of the few times to deviate from this guideline is when
null
is intentionally indicating something different from zero items. e.g. telephone number,null
for not set, empty for no phone number
- Iterators,
IEnumerator<T>
andIEnumerator
- If classes want to support iteration using the foreach loop construct, they must implement the enumerator pattern.
- Defining
- Syntax
- the class should derive from
IEnumerable<T>
public IEnumerator<T> GetEnumerator() {}
method
- the class should derive from
- yield
- Iterators are like functions, but instead of returning values, they yield them. 生成一个个即将被iterate 的结果?
yield return SomeObject;
you can use yield only inGetEnumerator()
methods that returnIEnumerator<T>
, or in methods that returnIEnumerable<T>
but are not called GetEnumerator().- C# compiler generates the code to maintain the state machine for the iterator.
yield break;
- some other restrictions: P649
17 Reflection, Attributes, and Dynamic Programming 651
Reflection is the process of examining the metadata within an assembly.
- Accessing Metadata Using
System.Type
GetType()
typeof()
- Member Invocation
type.GetProperty()
andproperty.SetValue()
see examples
- Reflection on Generics
type.IsGenericType
foreach(Type type in t.GetGenericArguments()) {}
- Custom Attributes
- attributes are a means of associating additional data with a property (and other constructs).
- Language Contrast: Attributes are to C# what annotations are to Java
- 2 ways to combine
[Attr1] [Attr2]
[Attr1, Attr2]
- custom attributes
public class CLISwitchRequiredAttribute : Attribute {}
- get custom attributes
Attribute[] a = (Attribute[])property.GetCustomAttributes(...)
- Attribute Constructors
public class CLISwitchRequiredAttribute : Attribute { CLISwitchAliasAttribute(string alias) {Alias = alias;}}
- Named Parameters
- Predefined Attributes
AttributeUsageAttribute
before the attribute class to set target propertiesConditionalAttribute("CONDITION_BLAH")
before the methods to call on condition of#define CONDITION_BLAH
ObsoleteAttribute
causes a compile-time warning, optionally an error.Serializable
before class for storageNonSerializable
- version problem?
System.Runtime.Serialization.OptionalFieldAttribute
- Dynamic Objects
- Dynamic object support provides a common solution for talking to runtime environments that don’t necessarily have a compile-time-defined structure.
- The key difference when using a dynamic object is that it is necessary to identify the signature at compile time, rather than determine things such as the member name at runtime (like we did when parsing the command-line arguments).
- TODO
1 2 3 4 5 6 7 |
|
18 Multithreading 701
thread, time slicing.
In .NET Framework 4, the task requests a thread from the thread pool.
Task
in Task Parallel Libraryclass Task(Delegate Func);
andclass Task<TResult>(Delegate Func)
task.Result
,task.IsCompleted
,task.Id
,task.AsyncState
, staticTask.CurrentId
,
Parallel Loops
Parallel.For()
Parallel.ForEach<T>()
- Unhanded Exceptions
- Parallel LINQ
- Multithreaded Programming with Tasks
- Task Basiscs
ContinueWith()
- Unhandled Exceptions
- TPL Cancellation Requests
- Canceling a Task
- Canceling Parallel Loops
- Canceling a Task
Multithreaded Programming before TPL (Before .NET 4)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
19 Multithreading Patterns 749
Thread-safe: Code or dada synchronized for simultaneous access by multiple threads.
torn read. When reading a variable requires more than one machine instruction, and another task writes to the variable between the read instructions.
Local variables are loaded onto the stack and each thread has its own logical stack. (But they can still be accessed by other threads.)
Synchronization
- Monitor
- use a monitor to block the second thread from entering a protected code section before the first thread has exited that section. See the example.
_Sync
object,try
/finally
- Lock
- Monitor is fallible with
try
/finally
(forgettable) - use a per-synchronization context instance of type object for the lock target.
- avoid locking
this
,typeof(type)
, andstring
TODO:??我的理解是不要从instance内部锁,一律从外部锁,防止死锁。
- Monitor is fallible with
Volatile Language Contrast:
- C#: ensures that code accessing the field is not subject to some thread unsafe optimizations that may be performed by the compiler, the CLR, or by hardware. (forces all reads and writes to the volatile field to occur at the exact location the code identifies instead of at some other location that the) optimization produces.
- Java: read its current value before continuing, instead of (potentially) using a cached value. Volatile reads and writes establish a happens-before relationship, much like acquiring and releasing a mutex.
- C: volatile exists for specifying special treatment for such locations, specifically: (1) the content of a volatile variable is “unstable” (can change by means unknown to the compiler), (2) all writes to volatile data are “observable” so they must be executed religiously, and (3) all operations on volatile data are executed in the sequence in which they appear in the source code.
- usage of volatile keyword as a portable synchronization mechanism is discouraged by many C/C++ groups.
System.Threading.Interlocked
- synchronization with System.Threading.Monitor is a relatively expensive operation
- If
_Data
isnull
then set it tonewValue
Interlocked.CompareExchange(ref _data, newValue, null);
- Synchronization Best Practices
- avoid deadlocks. Deadlock’s 4 conditions:
- Mutual exclusion
- Hold and wait
- No preemption
- Circular wait condition
- All static data should be thread-safe.
- programmers should declare private static variables and then provide public methods for modifying the data. Such methods should internally handle the synchronization.
- avoid deadlocks. Deadlock’s 4 conditions:
Mutex
- WaitHandle
- Reset Events
- reset events have nothing to do with C# delegates and events. Instead, reset events are a way to force code to wait for the execution of another thread until the other thread signals
- Favor
ManualResetEvent
andSemaphores
overAutoResetEvent
- Concurrent Collection Classes
- designed to include built-in synchronization code so that they can support simultaneous access by multiple threads without concern for race conditions.
BlockingCollection<T>
ConcurrentBag<T>
ConcurrentDictionary<TKey, TValue>
ConcurrentQueue<T>
ConcurrentStack<T>
- Monitor
- Thread Local Storage
ThreadLocal<T>
ThreadStaticAttribute
- Timers
- Asynchronous Programming Model (APM)
- the key aspect of the APM is the pair of
IAsyncResult BeginX()
andEndX()
methods with well-established signatures. WaitHandle
to determine when the asynchronous method completes.EndX()
- block further execution until the successful complete
- get the return data
- receive the exception
- clean up resources
- the key aspect of the APM is the pair of
- Background Worker Pattern
- TODO
- Windows UI Programming
- TODO
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 |
|
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 |
|
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 |
|
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 |
|
20 Platform Interoperability and Unsafe Code 815
- What if the memory addresses and pointers have be used?
- 3 ways
- Platform Invoke (P/Invoke)
- unsafe code
- COM
21 The Common Language Infrastructure 843
- TODO