mirror of
https://github.com/m-lamonaca/dev-notes.git
synced 2025-06-08 18:57:12 +00:00
Rename all file to kebab-case
This commit is contained in:
parent
ffc085d78a
commit
68ca4e4f86
117 changed files with 0 additions and 1260 deletions
2925
dotnet/C#/C#.md
Normal file
2925
dotnet/C#/C#.md
Normal file
File diff suppressed because it is too large
Load diff
195
dotnet/C#/async-programming.md
Normal file
195
dotnet/C#/async-programming.md
Normal file
|
@ -0,0 +1,195 @@
|
|||
# [Async Programming](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/)
|
||||
|
||||
## Task Asynchronous Programming Model ([TAP][tap_docs])
|
||||
|
||||
[tap_docs]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model
|
||||
|
||||
It's possible to avoid performance bottlenecks and enhance the overall responsiveness of an application by using asynchronous programming.
|
||||
However, traditional techniques for writing asynchronous applications can be complicated, making them difficult to write, debug, and maintain.
|
||||
|
||||
C# 5 introduced a simplified approach, **async programming**, that leverages asynchronous support in the .NET Runtime.
|
||||
The compiler does the difficult work that the developer used to do, and the application retains a logical structure that resembles synchronous code.
|
||||
|
||||
In performance-sensitive code, asynchronous APIs are useful, because instead of wasting resources by forcing a thread to sit and wait for I/O to complete, a thread can kick off the work and then do something else productive in the meantime.
|
||||
|
||||
The `async` and `await` keywords in C# are the heart of async programming.
|
||||
|
||||
```cs
|
||||
public async Task<TResult> MethodAsync
|
||||
{
|
||||
Task<TResult> resultTask = obj.OtherMethodAsync();
|
||||
|
||||
DoIndependentWork();
|
||||
|
||||
TResult result = await resultTask;
|
||||
|
||||
// if the is no work to be done before awaiting
|
||||
TResult result = await obj.OtherMethodAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
Characteristics of Async Methods:
|
||||
|
||||
- The method signature includes an `async` modifier.
|
||||
- The name of an async method, by convention, ends with an "Async" suffix.
|
||||
- The return type is one of the following types:
|
||||
- `Task<TResult>` if the method has a return statement in which the operand has type `TResult`.
|
||||
- `Task` if the method has no return statement or has a return statement with no operand.
|
||||
- `void` if it's an async event handler.
|
||||
- Any other type that has a `GetAwaiter` method (starting with C# 7.0).
|
||||
- Starting with C# 8.0, `IAsyncEnumerable<T>`, for an async method that returns an async stream.
|
||||
|
||||
The method usually includes at least one `await` expression, which marks a point where the method can't continue until the awaited asynchronous operation is complete.
|
||||
In the meantime, the method is suspended, and control returns to the method's caller.
|
||||
|
||||
### Threads
|
||||
|
||||
Async methods are intended to be non-blocking operations. An `await` expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.
|
||||
|
||||
The `async` and `await` keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. It's possible to use `Task.Run` to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.
|
||||
|
||||
The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than the `BackgroundWorker` class for I/O-bound operations because the code is simpler and there is no need to guard against race conditions.
|
||||
In combination with the `Task.Run` method, async programming is better than `BackgroundWorker` for CPU-bound operations because async programming separates the coordination details of running the code from the work that `Task.Run` transfers to the thread pool.
|
||||
|
||||
### Naming Convention
|
||||
|
||||
By convention, methods that return commonly awaitable types (for example, `Task`, `Task<T>`, `ValueTask`, `ValueTask<T>`) should have names that end with *Async*. Methods that start an asynchronous operation but do not return an awaitable type should not have names that end with *Async*, but may start with "Begin", "Start", or some other verb to suggest this method does not return or throw the result of the operation.
|
||||
|
||||
## [Async Return Types](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/async-return-types)
|
||||
|
||||
### `Task` return type
|
||||
|
||||
Async methods that don't contain a return statement or that contain a return statement that doesn't return an operand usually have a return type of `Task`. Such methods return `void` if they run synchronously.
|
||||
If a `Task` return type is used for an async method, a calling method can use an `await` operator to suspend the caller's completion until the called async method has finished.
|
||||
|
||||
### `Task<TResult>` return type
|
||||
|
||||
The `Task<TResult>` return type is used for an async method that contains a return statement in which the operand is `TResult`.
|
||||
|
||||
The `Task<TResult>.Result` property is a **blocking property**. If it's accessed it before its task is finished, the thread that's currently active is blocked until the task completes and the value is available.
|
||||
In most cases, access the value by using `await` instead of accessing the property directly.
|
||||
|
||||
### `void` return type
|
||||
|
||||
The `void` return type is used in asynchronous event handlers, which require a `void` return type. For methods other than event handlers that don't return a value, it's best to return a `Task` instead, because an async method that returns `void` can't be awaited.
|
||||
Any caller of such a method must continue to completion without waiting for the called async method to finish. The caller must be independent of any values or exceptions that the async method generates.
|
||||
|
||||
The caller of a void-returning async method *can't catch exceptions thrown from the method*, and such unhandled exceptions are likely to cause the application to fail.
|
||||
If a method that returns a `Task` or `Task<TResult>` throws an exception, the exception is stored in the returned task. The exception is re-thrown when the task is awaited.
|
||||
Therefore, make sure that any async method that can produce an exception has a return type of `Task` or `Task<TResult>` and that calls to the method are awaited.
|
||||
|
||||
### Generalized async return types and `ValueTask<TResult>`
|
||||
|
||||
Starting with C# 7.0, an async method can return any type that has an accessible `GetAwaiter` method.
|
||||
|
||||
Because `Task` and `Task<TResult>` are **reference types**, memory allocation in performance-critical paths, particularly when allocations occur in tight loops, can adversely affect performance. Support for generalized return types means that it's possible to return a lightweight **value type** instead of a reference type to avoid additional memory allocations.
|
||||
|
||||
.NET provides the `System.Threading.Tasks.ValueTask<TResult>` structure as a lightweight implementation of a generalized task-returning value. To use the `System.Threading.Tasks.ValueTask<TResult>` type, add the **System.Threading.Tasks.Extensions** NuGet package to the project.
|
||||
|
||||
### Async Composition
|
||||
|
||||
```cs
|
||||
public async Task DoOperationsConcurrentlyAsync()
|
||||
{
|
||||
Task[] tasks = new Task[3];
|
||||
tasks[0] = DoOperation0Async();
|
||||
tasks[1] = DoOperation1Async();
|
||||
tasks[2] = DoOperation2Async();
|
||||
|
||||
// At this point, all three tasks are running at the same time.
|
||||
|
||||
// Now, we await them all.
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public async Task<int> GetFirstToRespondAsync()
|
||||
{
|
||||
// Call two web services; take the first response.
|
||||
Task<int>[] tasks = new[] { WebService1Async(), WebService2Async() };
|
||||
|
||||
// Await for the first one to respond.
|
||||
Task<int> firstTask = await Task.WhenAny(tasks);
|
||||
|
||||
// Return the result.
|
||||
return await firstTask;
|
||||
}
|
||||
```
|
||||
|
||||
### Execution & Synchronization Context
|
||||
|
||||
When the program’s execution reaches an `await` expression for an operation that doesn’t complete immediately, the code generated for that `await` will ensure that the
|
||||
current execution context has been captured.
|
||||
When the asynchronous operation completes, the remainder of the method will be executed through the execution context.
|
||||
The execution context handles certain contextual information that needs to flow when one method invokes another (even when it does so indirectly)
|
||||
|
||||
While all `await` expressions capture the *execution context*, the decision of whether to flow *synchronization context* as well is controlled by the type being awaited.
|
||||
|
||||
Sometimes, it's better to avoid getting the synchronization context involved.
|
||||
If work starting from a UI thread is performed, but there is no particular need to remain on that thread, scheduling every continuation through the synchronization context is unnecessary overhead.
|
||||
|
||||
If the asynchronous operation is a `Task`, `Task<T>`, `ValueTask` or `ValueTask<T>`, it's possible to discard the *synchronization context* by calling the `ConfigureAwait(false)`.
|
||||
This returns a different representation of the asynchronous operation, and if this iss awaited that instead of the original task, it will ignore the current `SynchronizationContext` if there is one.
|
||||
|
||||
```cs
|
||||
private async Task DownloadFileAsync(string fileName)
|
||||
{
|
||||
await OperationAsync(fileName).ConfigureAwait(false); // discarding original context
|
||||
}
|
||||
```
|
||||
|
||||
When writing libraries in most cases you it'ss best to call `ConfigureAwait(false)` anywhere `await` is used.
|
||||
This is because continuing via the synchronization context can be expensive, and in some cases it can introduce the possibility of deadlock occurring.
|
||||
|
||||
The only exceptions are when are doing something that positively requires the synchronization context to be preserved, or it's know for certain that the library will only ever be used in
|
||||
application frameworks that do not set up a synchronization context.
|
||||
(ASP.NET Core applications do not use synchronization contexts, so it generally doesn’t matter whether or not `ConfigureAwait(false)` is called in those)
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Argument Validation
|
||||
|
||||
Inside an `async` method, the compiler treats all exceptions in the same way: none are allowed to pass up the stack as in a normal method, and they will always be reported by faulting the returned task.
|
||||
This is true even of exceptions thrown before the first `await`.
|
||||
|
||||
If the calling method immediately calls `await` on the return task, this won’t matter much—it will see the exception in any case.
|
||||
But some code may choose not to wait immediately, in which case it won’t see the argument exception until later.
|
||||
|
||||
```cs
|
||||
async Task<string> MethodWithValidationAsync(string argument)
|
||||
{
|
||||
if(sting.IsNullOrEmpty(argument))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(argument)); // will be thrown on await of MethodWithValidationAsync
|
||||
}
|
||||
|
||||
// [...]
|
||||
|
||||
return await LongOperationAsync();
|
||||
}
|
||||
```
|
||||
|
||||
In cases where you want to throw this kind of exception straightaway, the usual technique is to write a normal method that validates the arguments before calling an async method that does the
|
||||
work, and to make that second method either private or local.
|
||||
|
||||
```cs
|
||||
// not marked with async, exception propagate directly to caller
|
||||
public static Task<string> MethodWithValidationAsync(string argument)
|
||||
{
|
||||
if(sting.IsNullOrEmpty(argument))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(argument)); // thrown immediately
|
||||
}
|
||||
|
||||
return ActualMethodAsync(argument); // pass up task of inner method
|
||||
}
|
||||
|
||||
private static async Task<string> ActualMethodAsync(string argument)
|
||||
{
|
||||
// [...]
|
||||
return await LongOperationAsync();
|
||||
}
|
||||
```
|
||||
|
||||
**NOTE**: `await` extracts only the first exception of an `AggregateException`, this can cause the loss of information if a task (or group of tasks) has more than one error.
|
296
dotnet/C#/collections.md
Normal file
296
dotnet/C#/collections.md
Normal file
|
@ -0,0 +1,296 @@
|
|||
# C# Collections
|
||||
|
||||
## Arrays
|
||||
|
||||
An array is an object that contains multiple elements of a particular type. The number of elements is fixed for the lifetime of the array, so it must be specified when the array is created.
|
||||
|
||||
An array type is always a reference type, regardless of the element type. Nonetheless, the choice between reference type and value type elements makes a significant difference in an array's behavior.
|
||||
|
||||
```cs
|
||||
type[] array = new type[dimension];
|
||||
type array[] = new type[dimension]; //invalid
|
||||
|
||||
type[] array = {value1, value2, ..., valueN}; // initializer
|
||||
var array = new type[] {value1, value2, ..., valueN}; // initializer (var type needs new operator)
|
||||
var array = new[] {value1, value2, ..., valueN}; // initializer w/ element type inference (var type needs new operator), can be used as method arg
|
||||
|
||||
array[index]; // value access
|
||||
array[index] = value; // value assignment
|
||||
array.Length; // dimension of the array
|
||||
|
||||
// from IEnumerable<T>
|
||||
array.OfType<Type>(); // filter array based on type, returns IEnumerable<Type>
|
||||
```
|
||||
|
||||
### [Array Methods](https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods)
|
||||
|
||||
```cs
|
||||
// overloaded search methods
|
||||
Array.IndexOf(array, item); // return index of searched item in passed array
|
||||
Array.LastIndexOf(array, item); // return index of searched item staring from the end of the array
|
||||
Array.FindIndex(array, Predicate<T>) // returns the index of the first item matching the predicate (can be lambda function)
|
||||
Array.FindLastIndex(array, Predicate<T>) // returns the index of the last item matching the predicate (can be lambda function)
|
||||
Array.Find(array, Predicate<T>) // returns the value of the first item matching the predicate (can be lambda function)
|
||||
Array.FindLast(array, Predicate<T>) // returns the value of the last item matching the predicate (can be lambda function)
|
||||
Array.FindAll(array, Predicate<T>) // returns array of all items matching the predicate (can be lambda function)
|
||||
Array.BinarySearch(array, value) // Searches a SORTED array for a value, using a binary search algorithm; returns the index of the found item
|
||||
|
||||
Array.Sort(array);
|
||||
Array.Reverse(array); // reverses the order of array elements
|
||||
Array.Clear(start_index, x); //removes reference to x elements starting at start index. Dimension of array unchanged (cleared elements value is set tu null)
|
||||
Array.Resize(ref array, target_dimension); //expands or shrinks the array dimension. Shrinking drops trailing values. Array passed by reference.
|
||||
|
||||
// Copies elements from an Array starting at the specified index and pastes them to another Array starting at the specified destination index.
|
||||
Array.Copy(sourceArray, sourceStartIndex, destinationArray, destinationStartIndex, numItemsToCopy);
|
||||
// Copies elements from an Array starting at the first element and pastes them into another Array starting at the first element.
|
||||
Array.Copy(sourceArray, destinationArray, numItemsToCopy);
|
||||
Array.Clone(); // returns a shallow copy of the array
|
||||
```
|
||||
|
||||
### Multidimensional Arrays
|
||||
|
||||
C# supports two multidimensional array forms: [jagged][jagg_arrays] arrays and [rectangular][rect_arrays] arrays (*matrices*).
|
||||
|
||||
[jagg_arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/jagged-arrays
|
||||
[rect_arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays
|
||||
|
||||
```cs
|
||||
//specify first dimension
|
||||
type[][] jagged = new type[][]
|
||||
{
|
||||
new[] {item1, item2, item3},
|
||||
new[] {item1},
|
||||
new[] {item1, item2},
|
||||
...
|
||||
}
|
||||
|
||||
// shorthand
|
||||
type[][] jagged =
|
||||
{
|
||||
new[] {item1, item2, item3},
|
||||
new[] {item1},
|
||||
new[] {item1, item2},
|
||||
...
|
||||
}
|
||||
|
||||
// matrices
|
||||
type[,] matrix = new type[n, m]; // n * m matrix
|
||||
type[,] matrix = {{}, {}, {}, ...}; // {} for each row to initialize
|
||||
type[, ,] tensor = new type[n, m, o] // n * m * o tensor
|
||||
|
||||
matrix.Length; // total number of elements (n * m)
|
||||
matrix.GetLength(int dimension); // get the size of a particular direction
|
||||
// row = 0, column = 1, ...
|
||||
```
|
||||
|
||||
## [Lists](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1)
|
||||
|
||||
`List<T>` stores sequences of elements. It can grow or shrink, allowing to add or remove elements.
|
||||
|
||||
```cs
|
||||
using System.Collections.Generics;
|
||||
|
||||
List<T> list = new List<T>();
|
||||
List<T> list = new List<T> {item_1, ...}; // initialized usable since list implements IEnumerable<T> and has Add() method (even extension method)
|
||||
List<T> list = new List<T>(dimension); // set list starting dimension
|
||||
List<T> list = new List<T>(IEnumerable<T>); // create a list from an enumerable collection
|
||||
|
||||
|
||||
list.Add(item); //item insertion into the list
|
||||
list.AddRange(IEnumerable<T> collection); // insert multiple items
|
||||
list.Insert(index, item); // insert an item at the specified index
|
||||
list.InsertRange(index, item); // insert items at the specified index
|
||||
|
||||
list.IndexOf(item); // return index of searched item in passed list
|
||||
list.LastIndexOf(item); // return index of searched item staring from the end of the array
|
||||
list.FindIndex(Predicate<T>) // returns the index of the first item matching the predicate (can be lambda function)
|
||||
list.FindLastIndex(Predicate<T>) // returns the index of the last item matching the predicate (can be lambda function)
|
||||
list.Find(Predicate<T>) // returns the value of the first item matching the predicate (can be lambda function)
|
||||
list.FindLast(Predicate<T>) // returns the value of the last item matching the predicate (can be lambda function)
|
||||
list.FindAll(Predicate<T>) // returns list of all items matching the predicate (can be lambda function)
|
||||
list.BinarySearch(value) // Searches a SORTED list for a value, using a binary search algorithm; returns the index of the found item
|
||||
|
||||
list.Remove(item); // remove item from list
|
||||
list.RemoveAt(index); // remove item at specified position
|
||||
list.RemoveRange(index, quantity); // remove quantity items at specified position
|
||||
|
||||
list.Contains(item); // check if item is in the list
|
||||
list.TrueForAll(Predicate<T>); // Determines whether every element matches the conditions defined by the specified predicate
|
||||
|
||||
list[index]; // access to items by index
|
||||
list[index] = value; // modify to items by index
|
||||
list.Count; // number of items in the list
|
||||
|
||||
list.Sort(); // sorts item in crescent order
|
||||
list.Reverse(); // Reverses the order of the elements in the list
|
||||
|
||||
// from IEnumerable<T>
|
||||
list.OfType<Type>(); // filter list based on type, returns IEnumerable<Type>
|
||||
list.OfType<Type>().ToList(); // filter list based on type, returns List<Type>
|
||||
```
|
||||
|
||||
## [Iterators](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/iterators)
|
||||
|
||||
An iterator can be used to step through collections such as lists and arrays.
|
||||
|
||||
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.
|
||||
When a `yield return` statement is reached, the current location in code is remembered. Execution is restarted from that location the next time the iterator function is called.
|
||||
|
||||
It's possible to use a `yield break` statement or exception to end the iteration.
|
||||
|
||||
**Note**: Since an iterator returns an `IEnumerable<T>` is can be used to implement a `GetEnumerator()`.
|
||||
|
||||
```cs
|
||||
// simple iterator
|
||||
public static System.Collections.IEnumerable<int> IterateRange(int start = 0, int end)
|
||||
{
|
||||
for(int i = start; i < end; i++){
|
||||
yield return i;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## List & Sequence Interfaces
|
||||
|
||||
### [`IEnumerable<T>`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1)
|
||||
|
||||
Exposes the enumerator, which supports a simple iteration over a collection of a specified type.
|
||||
|
||||
```cs
|
||||
public interface IEnumerable<out T> : IEnumerable
|
||||
{
|
||||
IEnumerator<T> GetEnumerator(); // return an enumerator
|
||||
}
|
||||
|
||||
// iterate through a collection
|
||||
public interface IEnumerator<T>
|
||||
{
|
||||
// properties
|
||||
object Current { get; } // Get the element in the collection at the current position of the enumerator.
|
||||
|
||||
// methods
|
||||
void IDisposable.Dispose(); // Perform application-defined tasks associated with freeing, releasing, or resetting unmanaged resources
|
||||
bool MoveNext(); // Advance the enumerator to the next element of the collection.
|
||||
void Reset(); // Set the enumerator to its initial position, which is before the first element in the collection.
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: must call `Dispose()` on enumerators once finished with them, because many of them rely on this. `Reset()` is legacy and can, in some situations, throw `NotSupportedException()`.
|
||||
|
||||
### [`ICollection<T>`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.icollection-1)
|
||||
|
||||
```cs
|
||||
public interface ICollection<T> : IEnumerable<T>
|
||||
{
|
||||
// properties
|
||||
int Count { get; } // Get the number of elements contained in the ICollection<T>
|
||||
bool IsReadOnly { get; } // Get a value indicating whether the ICollection<T> is read-only
|
||||
|
||||
// methods
|
||||
void Add (T item); // Add an item to the ICollection<T>
|
||||
void Clear (); // Removes all items from the ICollection<T>
|
||||
bool Contains (T item); // Determines whether the ICollection<T> contains a specific value
|
||||
IEnumerator GetEnumerator (); // Returns an enumerator that iterates through a collection
|
||||
bool Remove (T item); // Removes the first occurrence of a specific object from the ICollection<T>
|
||||
}
|
||||
```
|
||||
|
||||
### [`IList<T>`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ilist-1)
|
||||
|
||||
```cs
|
||||
public interface IList<T> : ICollection<T>, IEnumerable<T>
|
||||
{
|
||||
// properties
|
||||
int Count { get; } // Get the number of elements contained in the ICollection<T>
|
||||
bool IsReadOnly { get; } // Get a value indicating whether the ICollection<T> is read-only
|
||||
T this[int index] { get; set; } // Get or set the element at the specified index
|
||||
|
||||
// methods
|
||||
void Add (T item); // Add an item to the ICollection<T>
|
||||
void Clear (); // Remove all items from the ICollection<T>
|
||||
bool Contains (T item); // Determine whether the ICollection<T> contains a specific value
|
||||
void CopyTo (T[] array, int arrayIndex); // Copy the elements of the ICollection<T> to an Array, starting at a particular Array index
|
||||
IEnumerator GetEnumerator (); // Return an enumerator that iterates through a collection
|
||||
int IndexOf (T item); // Determine the index of a specific item in the IList<T>
|
||||
void Insert (int index, T item); // Insert an item to the IList<T> at the specified index
|
||||
bool Remove (T item); // Remove the first occurrence of a specific object from the ICollection<T>
|
||||
oid RemoveAt (int index); // Remove the IList<T> item at the specified index
|
||||
}
|
||||
```
|
||||
|
||||
## [Dictionaries](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2)
|
||||
|
||||
[ValueCollection](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.valuecollection)
|
||||
[KeyCollection](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.keycollection)
|
||||
|
||||
**Notes**:
|
||||
|
||||
- Enumerating a dictionary will return `KeyValuePair<TKey, TValue>`.
|
||||
- The `Dictionary<TKey, TValue>` collection class relies on hashes to offer fast lookup (`TKey` should have a good `GetHashCode()`).
|
||||
|
||||
```cs
|
||||
Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>(); // init empty dict
|
||||
Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>(IEqualityComparer<TKey>); // specify key comparer (TKey must implement Equals() and GetHashCode())
|
||||
|
||||
// initializer (implicitly uses Add method)
|
||||
Dictionary<TKey, TValue> dict =
|
||||
{
|
||||
{ key, value }
|
||||
{ key, value },
|
||||
...
|
||||
}
|
||||
|
||||
// object initializer
|
||||
Dictionary<TKey, TValue> dict =
|
||||
{
|
||||
[key] = value,
|
||||
[key] = value,
|
||||
...
|
||||
}
|
||||
|
||||
// indexer access
|
||||
dict[key]; // read value associated with key (throws KeyNotFoundException if key does not exist)
|
||||
dict[key] = value; // modify value associated with key (throws KeyNotFoundException if key does not exist)
|
||||
|
||||
dict.Count; // number of key-value pair stored in the dict
|
||||
dict.Keys; // Dictionary<TKey,TValue>.KeyCollection containing the keys of the dict
|
||||
dict.Values; // Dictionary<TKey,TValue>.ValueCollection containing the values of the dict
|
||||
|
||||
dict.Add(key, value); // ArgumentException if the key already exists
|
||||
dict.Clear(); // empty the dictionary
|
||||
dict.ContainsKey(key); // check if a key is in the dictionary
|
||||
dict.ContainsValue(value); // check if a value is in the dictionary
|
||||
dict.Remove(key); // remove a key-value pair
|
||||
dict.Remove(key, out var); // remove key-value pair and copy TValue to var parameter
|
||||
dict.TryAdd(key, value); // adds a key-value pair; returns true if pair is added, false otherwise
|
||||
dict.TryGetValue(key, out var); // put the value associated with kay in the var parameter; true if the dict contains an element with the specified key, false otherwise.
|
||||
```
|
||||
|
||||
## [Sets](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1)
|
||||
|
||||
Collection of non duplicate items.
|
||||
|
||||
```cs
|
||||
HashSet<T> set = new HashSet<T>();
|
||||
|
||||
set.Add(T); // adds an item to the set; true if the element is added, false if the element is already present.
|
||||
set.Clear(); //Remove all elements from a HashSet<T> object.
|
||||
set.Contains(T); // Determine whether a HashSet<T> object contains the specified element.
|
||||
set.CopyTo(T[]); // Coy the elements of a HashSet<T> object to an array.
|
||||
set.CopyTo(T[], arrayIndex); // Copy the elements of a HashSet<T> object to an array, starting at the specified array index.
|
||||
set.CopyTo(T[], arrayIndex, count); // Copies the specified number of elements of a HashSet<T> object to an array, starting at the specified array index.
|
||||
set.CreateSetComparer(); // Return an IEqualityComparer object that can be used for equality testing of a HashSet<T> object.
|
||||
set.ExceptWith(IEnumerable<T>); // Remove all elements in the specified collection from the current HashSet<T> object.
|
||||
set.IntersectWith(IEnumerable<T>); // Modify the current HashSet<T> object to contain only elements that are present in that object and in the specified collection.
|
||||
set.IsProperSubsetOf(IEnumerable<T>); // Determine whether a HashSet<T> object is a proper subset of the specified collection.
|
||||
set.IsProperSupersetOf(IEnumerable<T>); // Determine whether a HashSet<T> object is a proper superset of the specified collection.
|
||||
set.IsSubsetOf(IEnumerable<T>); // Determine whether a HashSet<T> object is a subset of the specified collection.
|
||||
set.IsSupersetOf(IEnumerable<T>); // Determine whether a HashSet<T> object is a superset of the specified collection.
|
||||
set.Overlaps(IEnumerable<T>); // Determine whether the current HashSet<T> object and a specified collection share common elements.
|
||||
set.Remove(T); // Remove the specified element from a HashSet<T> object.
|
||||
set.RemoveWhere(Predicate<T>); // Remove all elements that match the conditions defined by the specified predicate from a HashSet<T> collection.
|
||||
set.SetEquals(IEnumerable<T>); // Determine whether a HashSet<T> object and the specified collection contain the same elements.
|
||||
set.SymmetricExceptWith(IEnumerable<T>); // Modify the current HashSet<T> object to contain only elements that are present either in that object or in the specified collection, but not both.
|
||||
set.UnionWith(IEnumerable<T>); // Modify the current HashSet<T> object to contain all elements that are present in itself, the specified collection, or both.
|
||||
set.TryGetValue(T, out T); // Search the set for a given value and returns the equal value it finds, if any.
|
||||
```
|
84
dotnet/C#/linq.md
Normal file
84
dotnet/C#/linq.md
Normal file
|
@ -0,0 +1,84 @@
|
|||
# LINQ
|
||||
|
||||
## LINQ to Objects
|
||||
|
||||
<!-- Page: 423/761 of "Ian Griffiths - Programming C# 8.0 - Build Cloud, Web, and Desktop Applications.pdf" -->
|
||||
|
||||
The term **LINQ to Objects** refers to the use of LINQ queries with any `IEnumerable` or `IEnumerable<T>` collection directly, without the use of an intermediate LINQ provider or API such as [LINQ to SQL](https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/linq/) or [LINQ to XML](https://docs.microsoft.com/en-us/dotnet/standard/linq/linq-xml-overview).
|
||||
|
||||
LINQ to Objects will be used when any `IEnumerable<T>` is specified as the source, unless a more specialized provider is available.
|
||||
|
||||
### Query Expressions
|
||||
|
||||
All query expressions are required to begin with a `from` clause, which specifies the source of the query.
|
||||
The final part of the query is a `select` (or `group`) clause. This determines the final output of the query and its system type.
|
||||
|
||||
```cs
|
||||
// query expression
|
||||
var result = from item in enumerable select item;
|
||||
|
||||
// where clause
|
||||
var result = from item in enumerable where condition select item;
|
||||
|
||||
// ordering
|
||||
var result = from item in enumerable orderby item.property select item; // ordered IEnumerable
|
||||
|
||||
// let clause, assign expression to variable to avoid re-evaluation on each cycle
|
||||
var result = from item in enumerable let tmp = <sub-expr> ... // BEWARE: compiled code has a lot of overhead to satisfy let clause
|
||||
|
||||
// grouping (difficult to re-implement to obtain better performance)
|
||||
var result = from item in enumerable group item by item.property; // returns IEnumerable<IGrouping<TKey,TElement>>
|
||||
```
|
||||
|
||||
### How Query Expressions Expand
|
||||
|
||||
The compiler converts all query expressions into one or more method calls. Once it has done that, the LINQ provider is selected through exactly the same mechanisms that C# uses for any other method call.
|
||||
The compiler does not have any built-in concept of what constitutes a LINQ provider.
|
||||
|
||||
```cs
|
||||
// expanded query expression
|
||||
var result = Enumerable.Where(item => condition).Select(item => item);
|
||||
```
|
||||
|
||||
The `Where` and `Select` methods are examples of LINQ operators. A LINQ operator is nothing more than a method that conforms to one of the standard patterns.
|
||||
|
||||
### Methods on `Enumerable` or `IEnumerable<T>`
|
||||
|
||||
```cs
|
||||
Enumerable.Range(int start, int end); // IEnumerable<int> of values between start & end
|
||||
|
||||
IEnumerable<TSource>.Select(Func<TSource, TResult> selector); // map
|
||||
IEnumerable<TSource>.Where(Func<T, bool> predicate); // filter
|
||||
|
||||
IEnumerable<T>.FirstOrDefault(); // first element of IEnumerable or default(T) if empty
|
||||
IEnumerable<T>.FirstOrDefault(T default); // specify returned default
|
||||
IEnumerable<T>.FirstOrDefault(Func<T, bool> predicate); // first element to match predicate or default(T)
|
||||
// same for LastOrDefault & SingleOrDefault
|
||||
|
||||
IEnumerable<T>.Chunk(size); // chunk an enumerable into slices of a fixed size
|
||||
|
||||
// T must implement IComparable<T>
|
||||
IEnumerable<T>.Max();
|
||||
IEnumerable<T>.Min();
|
||||
|
||||
// allow finding maximal or minimal elements using a key selector
|
||||
IEnumerable<TSource>.MaxBy(Func<TSource, TResult> selector);
|
||||
IEnumerable<TSource>.MinBy(Func<TSource, TResult> selector);
|
||||
|
||||
IEnumerable<T>.All(Func<T, bool> predicate); // check if condition is true for all elements
|
||||
IEnumerable<T>.Any(Func<T, bool> predicate); // check if condition is true for at least one element
|
||||
|
||||
IEnumerable<T>.Concat(IEnumerable<T> enumerable);
|
||||
|
||||
// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
|
||||
IEnumerable<TFirst>.Zip(IEnumerable<TSecond> enumerable, Func<TFirst, TSecond, TResult> func);
|
||||
IEnumerable<TFirst>.Zip(IEnumerable<TSecond> enumerable); // Produces a sequence of tuples with elements from the two specified sequences.
|
||||
```
|
||||
|
||||
**NOTE**: `Enumerable` provides a set of `static` methods for querying objects that implement `IEnumerable<T>`. Most methods are extensions of `IEnumerable<T>`
|
||||
|
||||
```cs
|
||||
Enumerable.Method(IEnumerable<T> source, args);
|
||||
// if extension method same as
|
||||
IEnumerable<T>.Method(args);
|
||||
```
|
168
dotnet/C#/reactive-extensions.md
Normal file
168
dotnet/C#/reactive-extensions.md
Normal file
|
@ -0,0 +1,168 @@
|
|||
# Reactive Extensions (Rx)
|
||||
|
||||
[ReactiveX](https://reactivex.io "ReactiveX website")
|
||||
|
||||
The **Reactive Extensions** for .NET, or **Rx**, are designed for working with asynchronous and event-based sources of information.
|
||||
Rx provides services that help orchestrate and synchronize the way code reacts to data from these kinds of sources.
|
||||
|
||||
Rx's fundamental abstraction, `IObservable<T>`, represents a sequence of items, and its operators are defined as extension methods for this interface.
|
||||
|
||||
This might sound a lot like LINQ to Objects, and there are similarities, not only does `IObservable<T>` have a lot in common with `IEnumerable<T>`, but Rx also supports almost all of the standard LINQ operators.
|
||||
|
||||
The difference is that in Rx, sequences are less passive. Unlike `IEnumerable<T>`, Rx sources do not wait to be asked for their items, nor can the consumer
|
||||
of an Rx source demand to be given the next item. Instead, Rx uses a *push* model in which *the source notifies* its recipients when items are available.
|
||||
|
||||
Because Rx implements standard LINQ operators, it's possible to write queries against a live source. Rx goes beyond standard LINQ, adding its own operators that take into account the temporal nature of a live event source.
|
||||
|
||||
## Fundamental Interfaces
|
||||
|
||||
The two most important types in Rx are the `IObservable<T>` and `IObserver<T>` interfaces.
|
||||
They are important enough to be in the System namespace. The other parts of Rx are in the `System.Reactive` NuGet package.
|
||||
|
||||
```cs
|
||||
public interface IObservable<out T>
|
||||
{
|
||||
IDisposable Subscribe(IObserver<T> observer);
|
||||
}
|
||||
|
||||
public interface IObserver<in T>
|
||||
{
|
||||
void OnCompleted();
|
||||
void OnError(Exception error);
|
||||
void OnNext(T value);
|
||||
}
|
||||
```
|
||||
|
||||
The fundamental abstraction in Rx, `IObservable<T>`, is implemented by *event sources*. Instead of using the `event` keyword, it models events as a *sequence of items*.
|
||||
An `IObservable<T>` provides items to subscribers as and when it’s ready to do so.
|
||||
|
||||
It's possible to subscribe to a source by passing an implementation of `IObserver<T>` to the `Subscribe` method.
|
||||
The source will invoke `OnNext` when it wants to report events, and it can call `OnCompleted` to indicate that there will be no further activity.
|
||||
If the source wants to report an error, it can call `OnError`.
|
||||
Both `OnCompleted` and `OnError` indicate the end of the stream, an observable should not call any further methods on the observer after that.
|
||||
|
||||
## Operators
|
||||
|
||||
### Chaining Operators
|
||||
|
||||
Most operators operate on an Observable and return an Observable. This allows to apply these operators one after the other, in a chain.
|
||||
Each operator in the chain modifies the Observable that results from the operation of the previous operator.
|
||||
A chain of Observable operators do not operate independently on the original Observable that originates the chain,
|
||||
but they operate *in turn*, each one operating on the Observable generated by the operator immediately previous in the chain.
|
||||
|
||||
### Creating Observables
|
||||
|
||||
Operators that originate new Observables.
|
||||
|
||||
- `Create`: create an Observable from scratch by calling observer methods programmatically
|
||||
- `Defer`: do not create the Observable until the observer subscribes, and create a fresh Observable for each observer
|
||||
- `Empty/Never/Throw`: create Observables that have very precise and limited behavior
|
||||
- `From*`: convert some other object or data structure into an Observable
|
||||
- `Interval`: create an Observable that emits a sequence of integers spaced by a particular time interval
|
||||
- `Return (aka Just)`: convert an object or a set of objects into an Observable that emits that or those objects
|
||||
- `Range`: create an Observable that emits a range of sequential integers
|
||||
- `Repeat`: create an Observable that emits a particular item or sequence of items repeatedly
|
||||
- `Start`: create an Observable that emits the return value of a function
|
||||
- `Timer`: create an Observable that emits a single item after a given delay
|
||||
|
||||
### Transforming Observables
|
||||
|
||||
Operators that transform items that are emitted by an Observable.
|
||||
|
||||
- `Buffer`: periodically gather items from an Observable into bundles and emit these bundles rather than emitting the items one at a time
|
||||
- `SelectMany (aka FlatMap)`: transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable
|
||||
- `GroupBy`: divide an Observable into a set of Observables that each emit a different group of items from the original Observable, organized by key
|
||||
- `Select (aka Map)`: transform the items emitted by an Observable by applying a function to each item
|
||||
- `Scan`: apply a function to each item emitted by an Observable, sequentially, and emit each successive value
|
||||
- `Window`: periodically subdivide items from an Observable into Observable windows and emit these windows rather than emitting the items one at a time
|
||||
|
||||
### Filtering Observables
|
||||
|
||||
Operators that selectively emit items from a source Observable.
|
||||
|
||||
- `Throttle (aka Debounce)`: only emit an item from an Observable if a particular timespan has passed without it emitting another item
|
||||
- `Distinct`: suppress duplicate items emitted by an Observable
|
||||
- `ElementAt`: emit only item n emitted by an Observable
|
||||
- `Where (aka Filter)`: emit only those items from an Observable that pass a predicate test
|
||||
- `First`: emit only the first item, or the first item that meets a condition, from an Observable
|
||||
- `IgnoreElements`: do not emit any items from an Observable but mirror its termination notification
|
||||
- `Last`: emit only the last item emitted by an Observable
|
||||
- `Sample`: emit the most recent item emitted by an Observable within periodic time intervals
|
||||
- `Skip`: suppress the first n items emitted by an Observable
|
||||
- `SkipLast`: suppress the last n items emitted by an Observable
|
||||
- `Take`: emit only the first n items emitted by an Observable
|
||||
- `TakeLast`: emit only the last n items emitted by an Observable
|
||||
|
||||
### Combining Observables
|
||||
|
||||
Operators that work with multiple source Observables to create a single Observable
|
||||
|
||||
- `And/Then/When`: combine sets of items emitted by two or more Observables by means of Pattern and Plan intermediaries
|
||||
- `CombineLatest`: when an item is emitted by either of two Observables, combine the latest item emitted by each Observable via a specified function and emit items based on the results of this function
|
||||
- `Join`: combine items emitted by two Observables whenever an item from one Observable is emitted during a time window defined according to an item emitted by the other Observable
|
||||
- `Merge`: combine multiple Observables into one by merging their emissions
|
||||
- `StartWith`: emit a specified sequence of items before beginning to emit the items from the source Observable
|
||||
- `Switch`: convert an Observable that emits Observables into a single Observable that emits the items emitted by the most-recently-emitted of those Observables
|
||||
- `Zip`: combine the emissions of multiple Observables together via a specified function and emit single items for each combination based on the results of this function
|
||||
|
||||
### Error Handling Operators
|
||||
|
||||
Operators that help to recover from error notifications from an Observable
|
||||
|
||||
- `Catch`: recover from an onError notification by continuing the sequence without error
|
||||
- `Retry`: if a source Observable sends an onError notification, resubscribe to it in the hopes that it will complete without error
|
||||
|
||||
### Observable Utility Operators
|
||||
|
||||
A toolbox of useful Operators for working with Observables
|
||||
|
||||
- `Delay`: shift the emissions from an Observable forward in time by a particular amount
|
||||
- `Do`: register an action to take upon a variety of Observable lifecycle events
|
||||
- `Materialize/Dematerialize`: represent both the items emitted and the notifications sent as emitted items, or reverse this process
|
||||
- `ObserveOn`: specify the scheduler on which an observer will observe this Observable
|
||||
- `Synchronize (aka Serialize)`: force an Observable to make serialized calls and to be well-behaved
|
||||
- `Subscribe`: operate upon the emissions and notifications from an Observable
|
||||
- `SubscribeOn`: specify the scheduler an Observable should use when it is subscribed to
|
||||
- `TimeInterval`: convert an Observable that emits items into one that emits indications of the amount of time elapsed between those emissions
|
||||
- `Timeout`: mirror the source Observable, but issue an error notification if a particular period of time elapses without any emitted items
|
||||
- `Timestamp`: attach a timestamp to each item emitted by an Observable
|
||||
- `Using`: create a disposable resource that has the same lifespan as the Observable
|
||||
|
||||
### Conditional and Boolean Operators
|
||||
|
||||
Operators that evaluate one or more Observables or items emitted by Observables
|
||||
|
||||
- `All`: determine whether all items emitted by an Observable meet some criteria
|
||||
- `Amb`: given two or more source Observables, emit all of the items from only the first of these Observables to emit an item
|
||||
- `Contains`: determine whether an Observable emits a particular item or not
|
||||
- `DefaultIfEmpty`: emit items from the source Observable, or a default item if the source Observable emits nothing
|
||||
- `SequenceEqual`: determine whether two Observables emit the same sequence of items
|
||||
- `SkipUntil`: discard items emitted by an Observable until a second Observable emits an item
|
||||
- `SkipWhile`: discard items emitted by an Observable until a specified condition becomes false
|
||||
- `TakeUntil`: discard items emitted by an Observable after a second Observable emits an item or terminates
|
||||
- `TakeWhile`: discard items emitted by an Observable after a specified condition becomes false
|
||||
|
||||
### Mathematical and Aggregate Operators
|
||||
|
||||
Operators that operate on the entire sequence of items emitted by an Observable
|
||||
|
||||
- `Average`: calculates the average of numbers emitted by an Observable and emits this average
|
||||
- `Concat`: emit the emissions from two or more Observables without interleaving them
|
||||
- `Count`: count the number of items emitted by the source Observable and emit only this value
|
||||
- `Max`: determine, and emit, the maximum-valued item emitted by an Observable
|
||||
- `Min`: determine, and emit, the minimum-valued item emitted by an Observable
|
||||
- `Aggregate (aka Reduce)`: apply a function to each item emitted by an Observable, sequentially, and emit the final value
|
||||
- `Sum`: calculate the sum of numbers emitted by an Observable and emit this sum
|
||||
|
||||
### Connectable Observable Operators
|
||||
|
||||
Specialty Observables that have more precisely-controlled subscription dynamics
|
||||
|
||||
- `Connect`: instruct a connectable Observable to begin emitting items to its subscribers
|
||||
- `Publish`: convert an ordinary Observable into a connectable Observable
|
||||
- `RefCount`: make a Connectable Observable behave like an ordinary Observable
|
||||
- `Replay`: ensure that all observers see the same sequence of emitted items, even if they subscribe after the Observable has begun emitting items
|
||||
|
||||
### Operators to Convert Observables
|
||||
|
||||
- `To*`: convert an Observable into another object or data structure
|
51
dotnet/C#/unit-tests.md
Normal file
51
dotnet/C#/unit-tests.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Unit Testing
|
||||
|
||||
[UnitTest Overloaded Methods](https://stackoverflow.com/a/5666591/8319610)
|
||||
[Naming standards for unit tests](https://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html)
|
||||
|
||||
## xUnit
|
||||
|
||||
```cs
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
namespace Project.Tests
|
||||
{
|
||||
public class ClassTest
|
||||
{
|
||||
[Fact]
|
||||
public void TestMethod()
|
||||
{
|
||||
Assert.Equal(expected, actual); // works on collections
|
||||
Assert.True(bool);
|
||||
Assert.False(bool);
|
||||
Assert.NotNull(nullable);
|
||||
|
||||
// Verifies that all items in the collection pass when executed against action
|
||||
Assert.All<T>(IEnumerable<T> collection, Action<T> action);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Test Setup & Teardown
|
||||
|
||||
xUnit.net creates a new instance of the test class for every test that is run, so any code which is placed into the constructor of the test class will be run for every single test.
|
||||
This makes the constructor a convenient place to put reusable context setup code.
|
||||
|
||||
For context cleanup, add the `IDisposable` interface to the test class, and put the cleanup code in the `Dispose()` method.
|
||||
|
||||
## Mocking with Moq
|
||||
|
||||
```cs
|
||||
var mockObj = new Mock<MockedType>();
|
||||
|
||||
mockObj.Setup(m => m.Method(It.IsAny<InputType>())).Returns(value);
|
||||
mockObj.Object; // get mock
|
||||
|
||||
// check that the invocation is forwarded to the mock, n times
|
||||
mockObj.Verify(m => m.Method(It.IsAny<InputType>()), Times.Once());
|
||||
|
||||
// check that the invocation is forwarded to the mock with a specific input
|
||||
mockObj.Verify(m => m.Method(input), Times.Once());
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue