mirror of
https://github.com/m-lamonaca/dev-notes.git
synced 2025-04-07 11:26:41 +00:00
Fix typos, line endings and some stylization
This commit is contained in:
parent
3e66852ee4
commit
42a2fb1f71
1 changed files with 145 additions and 123 deletions
|
@ -354,7 +354,8 @@ This means that in accordance with their “value-ness” two record objects can
|
||||||
### `with`-expressions & Inheriance
|
### `with`-expressions & Inheriance
|
||||||
|
|
||||||
Records have a hidden virtual method that is entrusted with “cloning” the whole object.
|
Records have a hidden virtual method that is entrusted with “cloning” the whole object.
|
||||||
Every derived record type overrides this method to call the copy constructor of that type, and the copy constructor of a derived record chains to the copy constructor of the base record. A with-expression simply calls the hidden “clone” method and applies the object initializer to the result.
|
Every derived record type overrides this method to call the copy constructor of that type, and the copy constructor of a derived record chains to the copy constructor of the base record.
|
||||||
|
A with-expression simply calls the hidden “clone” method and applies the object initializer to the result.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
public record Base{ Type Prop1, Type Prop2 };
|
public record Base{ Type Prop1, Type Prop2 };
|
||||||
|
@ -577,8 +578,8 @@ The `ToString` method converts the current value of any variable into a textual
|
||||||
The rule for rounding (in explicit casting) in C# is subtly different from the primary school rule:
|
The rule for rounding (in explicit casting) in C# is subtly different from the primary school rule:
|
||||||
|
|
||||||
- It always rounds _down_ if the decimal part is less than the midpoint `.5`.
|
- It always rounds _down_ if the decimal part is less than the midpoint `.5`.
|
||||||
- It always rounds _up_ if the decimal part is more than the midpoint _.5_.
|
- It always rounds _up_ if the decimal part is more than the midpoint `.5`.
|
||||||
- It will round _up_ if the decimal part is the midpoint .5 and the non-decimal part is odd, but it will round _down_ if the non-decimal part is even.
|
- It will round _up_ if the decimal part is the midpoint `.5` and the non-decimal part is odd, but it will round _down_ if the non-decimal part is even.
|
||||||
|
|
||||||
This rule is known as **Banker's Rounding**, and it is preferred because it reduces bias by alternating when it rounds up or down.
|
This rule is known as **Banker's Rounding**, and it is preferred because it reduces bias by alternating when it rounds up or down.
|
||||||
|
|
||||||
|
@ -607,12 +608,15 @@ randomNumber = rand.NextDouble(); // random number between 0.0 and 1.0
|
||||||
|
|
||||||
## Preprocessor Directives
|
## Preprocessor Directives
|
||||||
|
|
||||||
C# offers a `#define` directive that lets you define a compilation symbol. These symmbols are commonly used in conjunction with the `#if` directive to compile code in diffferent ways for different situations.
|
C# offers a `#define` directive that lets you define a compilation symbol.
|
||||||
|
These symmbols are commonly used in conjunction with the `#if` directive to compile code in diffferent ways for different situations.
|
||||||
It’s common to define compilation symbols through the _compiler build settings_: open up the `.csproj` file and define the values you want in a `<DefineConstants>` element of any `<PropertyGroup>`.
|
It’s common to define compilation symbols through the _compiler build settings_: open up the `.csproj` file and define the values you want in a `<DefineConstants>` element of any `<PropertyGroup>`.
|
||||||
|
|
||||||
Compilation symbols are typically used in conjunction with the `#if`, `#else`, `#elif`, and `#endif` directives (`#if false` also exists).
|
Compilation symbols are typically used in conjunction with the `#if`, `#else`, `#elif`, and `#endif` directives (`#if false` also exists).
|
||||||
|
|
||||||
The _.NET SDK_ defines certain symbols by default. It supports two configurations: **Debug** and **Release**. It defines a `DEBUG` compilation symbol in the Debug configuration, whereas Release will define `RELEASE` instead. It defines a symbol called `TRACE` in both configurations.
|
The _.NET SDK_ defines certain symbols by default. It supports two configurations: **Debug** and **Release**.
|
||||||
|
It defines a `DEBUG` compilation symbol in the Debug configuration, whereas Release will define `RELEASE` instead.
|
||||||
|
It defines a symbol called `TRACE` in both configurations.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -620,7 +624,9 @@ The _.NET SDK_ defines certain symbols by default. It supports two configuration
|
||||||
#endif
|
#endif
|
||||||
```
|
```
|
||||||
|
|
||||||
C# provides a more subtle mechanism to support this sort of thing, called a _conditional method_. The compiler recognizes an attribute defined by the .NET class libraries, called `ConditionalAttribute`, for which it provides special compiletime behavior. Method annotated with this attribute will not be present in a non-Debug release.
|
C# provides a more subtle mechanism to support this sort of thing, called a _conditional method_.
|
||||||
|
The compiler recognizes an attribute defined by the .NET class libraries, called `ConditionalAttribute`, for which it provides special compiletime behavior.
|
||||||
|
Method annotated with this attribute will not be present in a non-Debug release.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
[System.Diagnostics.Conditional("DEBUG")]
|
[System.Diagnostics.Conditional("DEBUG")]
|
||||||
|
@ -913,7 +919,7 @@ foreach (type item in iterabile)
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: Due to the use of an *iterator*, the variable declared in a foreach statement cannot be used to modify the value of the current item.
|
**NOTE**: Due to the use of an *iterator*, the variable declared in a foreach statement cannot be used to modify the value of the current item.
|
||||||
**NOTE**: From C# 9 it's possible to implement GetEnumerator() as an *extensione method* making enumrable an class that normally isn't.
|
**NOTE**: From C# 9 it's possible to implement `GetEnumerator()` as an *extensione method* making enumrable an class that normally isn't.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -1298,8 +1304,10 @@ This is why it’s OK for each operation performed with a value type to produce
|
||||||
|
|
||||||
The most important question is : does the identity of an instance matter? In otherwords, is the distinction between one object and another object important?
|
The most important question is : does the identity of an instance matter? In otherwords, is the distinction between one object and another object important?
|
||||||
|
|
||||||
An important and related question is: does an instance of the type contain state that changes over time? Modifiable value types tend to be problematic, because it’s all too easy to end up working with some copy of a value, and not the correct instance.
|
An important and related question is: does an instance of the type contain state that changes over time?
|
||||||
So it’susually a good idea for value types to be immutable. This doesn’t mean that variables of these types cannot be modified; it just means that to modify the variable, its contents must be repalced entirely with a different value.
|
Modifiable value types tend to be problematic, because it’s all too easy to end up working with some copy of a value, and not the correct instance.
|
||||||
|
So it’susually a good idea for value types to be immutable. This doesn’t mean that variables of these types cannot be modified;
|
||||||
|
it just means that to modify the variable, its contents must be repalced entirely with a different value.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
public struct Point
|
public struct Point
|
||||||
|
@ -1605,7 +1613,8 @@ Class? c = objWithIndexer == null ? null : onjWithIndexer[index];
|
||||||
|
|
||||||
### Abstract Classes
|
### Abstract Classes
|
||||||
|
|
||||||
The `abstract` modifier indicates that the thing being modified has a missing or incomplete implementation. The `abstract` modifier can be used with classes, methods, properties, indexers, and events.
|
The `abstract` modifier indicates that the thing being modified has a missing or incomplete implementation.
|
||||||
|
The `abstract` modifier can be used with classes, methods, properties, indexers, and events.
|
||||||
Use the `abstract` modifier in a class declaration to indicate that a class is intended only to be a base class of other classes, not instantiated on its own.
|
Use the `abstract` modifier in a class declaration to indicate that a class is intended only to be a base class of other classes, not instantiated on its own.
|
||||||
Members marked as `abstract` must be implemented by non-abstract classes that derive from the abstract class.
|
Members marked as `abstract` must be implemented by non-abstract classes that derive from the abstract class.
|
||||||
|
|
||||||
|
@ -1668,6 +1677,7 @@ IClonable.Clone(); // Creates a new object that is a copy of the current insta
|
||||||
### Deconstruction
|
### Deconstruction
|
||||||
|
|
||||||
Deconstruction is not limited to tuples. By providing a `Deconstruct(...)` method(s) C# allows to use the same syntax with the users types.
|
Deconstruction is not limited to tuples. By providing a `Deconstruct(...)` method(s) C# allows to use the same syntax with the users types.
|
||||||
|
|
||||||
**NOTE**: Types with a deconstructor can also use _positional pattern matching_.
|
**NOTE**: Types with a deconstructor can also use _positional pattern matching_.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
|
@ -1796,7 +1806,8 @@ public readonly struct Fraction
|
||||||
|
|
||||||
### Nested Types
|
### Nested Types
|
||||||
|
|
||||||
A type defined at _global scope_ can be only `public`or `internal`; private would'nt make sense since that makes something accessible only from within its containing type, and there is no containing type at global scope.
|
A type defined at _global scope_ can be only `public`or `internal`.
|
||||||
|
private wouldn't make sense since that makes something accessible only from within its containing type, and there is no containing type at global scope.
|
||||||
But a nested type does have a containing type, so if a nested type is `private`, that type can be used only from inside the type within which it is nested.
|
But a nested type does have a containing type, so if a nested type is `private`, that type can be used only from inside the type within which it is nested.
|
||||||
|
|
||||||
**NOTE**: Code in a nested type is allowed to use nonpublic members of its containing type. However, an instance of a nested type does not automatically get a reference to an instance of its containing type.
|
**NOTE**: Code in a nested type is allowed to use nonpublic members of its containing type. However, an instance of a nested type does not automatically get a reference to an instance of its containing type.
|
||||||
|
@ -1833,7 +1844,8 @@ public interface IContract<T> {} // interfaces can be generic
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: Interfaces are reference types. Despite this, it's possible tp implement interfaces on both classes and structs.
|
**NOTE**: Interfaces are reference types. Despite this, it's possible tp implement interfaces on both classes and structs.
|
||||||
However, be careful when doing so with a struct, because when getting hold of an interface-typed reference to a struct, it will be a reference to a _box_, which is effectively an object that holds a copy of a struct in a way that can be referred to via a reference.
|
However, be careful when doing so with a struct, because when getting hold of an interface-typed reference to a struct, it will be a reference to a _box_,
|
||||||
|
which is effectively an object that holds a copy of a struct in a way that can be referred to via a reference.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1995,7 +2007,8 @@ public class Derived
|
||||||
|
|
||||||
### Generics Inheritance
|
### Generics Inheritance
|
||||||
|
|
||||||
If you derive from a generic class, you must supply the type arguments it requires. You must provide concrete types unless your derived type is generic, in which case itcan use its own type parameters as arguments.
|
If you derive from a generic class, you must supply the type arguments it requires.
|
||||||
|
You must provide concrete types unless your derived type is generic, in which case itcan use its own type parameters as arguments.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
public class GenericBase1<T>
|
public class GenericBase1<T>
|
||||||
|
@ -2125,7 +2138,8 @@ public delegate bool Predicate<in T1, ...>(T1 arg1, ...);
|
||||||
|
|
||||||
### Type Compatibility
|
### Type Compatibility
|
||||||
|
|
||||||
Delegate types do not derive from one another. Any delegate type defined in C# will derive directly from `MulticastDelegate`. However, the type system supports certain implicit reference conversions for generic delegate types through covariance and contravariance. The rules arevery similar to those for interfaces.
|
Delegate types do not derive from one another. Any delegate type defined in C# will derive directly from `MulticastDelegate`.
|
||||||
|
However, the type system supports certain implicit reference conversions for generic delegate types through covariance and contravariance. The rules are very similar to those for interfaces.
|
||||||
|
|
||||||
## Anonymous Functions (Lambda Expressions)
|
## Anonymous Functions (Lambda Expressions)
|
||||||
|
|
||||||
|
@ -2281,10 +2295,12 @@ The C# compiler produces an assembly as its output, with an extension of either
|
||||||
Tools that understand the PE file format will recognize a .NET assembly as avalid, but rather dull, PE file.
|
Tools that understand the PE file format will recognize a .NET assembly as avalid, but rather dull, PE file.
|
||||||
The CLR essentially uses PE files as containers for a .NET-specific data format, so to classic Win32 tools, a C# DLL will not appear to export any APIs.
|
The CLR essentially uses PE files as containers for a .NET-specific data format, so to classic Win32 tools, a C# DLL will not appear to export any APIs.
|
||||||
|
|
||||||
With .NET Core 3.0 or later, .NET assemblies won't be built with an extension of `.exe`. Even project types that produce directly runnable outputs (such as console or WPF applications) produce a `.dll` as their primary output.
|
With .NET Core 3.0 or later, .NET assemblies won't be built with an extension of `.exe`.
|
||||||
|
Even project types that produce directly runnable outputs (such as console or WPF applications) produce a `.dll` as their primary output.
|
||||||
They also generate an executable file too, but it’s not a .NET assembly. It’s just a bootstrapper that starts theruntime and then loads and executes your application’s main assembly.
|
They also generate an executable file too, but it’s not a .NET assembly. It’s just a bootstrapper that starts theruntime and then loads and executes your application’s main assembly.
|
||||||
|
|
||||||
**NOTE**: C# compiles to a binary intermediate language (IL), which is not directly executable. The normal Windows mechanisms for loading and running the code in an executable or DLL won’t work with IL, because that can run only with the help of the CLR.
|
**NOTE**: C# compiles to a binary intermediate language (IL), which is not directly executable.
|
||||||
|
The normal Windows mechanisms for loading and running the code in an executable or DLL won’t work with IL, because that can run only with the help of the CLR.
|
||||||
|
|
||||||
### .NET MEtadata
|
### .NET MEtadata
|
||||||
|
|
||||||
|
@ -2293,7 +2309,8 @@ The CLR needs to have complete knowledge of all the types that the code uses to
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
It's possible to embed binary resources in a DLL alongside the code and metadata. To embed a file select "Embedded Rersource" as it's *Build Action* in the file prperties. This compiles a copy of the file into the assembly.
|
It's possible to embed binary resources in a DLL alongside the code and metadata. To embed a file select "Embedded Rersource" as it's *Build Action* in the file prperties.
|
||||||
|
This compiles a copy of the file into the assembly.
|
||||||
|
|
||||||
To extract the resource at runtime use the `Assembly` class's `GetManifestResourceSttream` method which is par of the **Reflection API**.
|
To extract the resource at runtime use the `Assembly` class's `GetManifestResourceSttream` method which is par of the **Reflection API**.
|
||||||
|
|
||||||
|
@ -2304,7 +2321,8 @@ It was possible to split the code and metadata across multiple modules, and it w
|
||||||
This feature was rarely used, and .NET Core does not support it. However, it’s necessary to know about it because some of its consequences persist.
|
This feature was rarely used, and .NET Core does not support it. However, it’s necessary to know about it because some of its consequences persist.
|
||||||
In particular, parts of the design of the Reflection API make no sense unless this feature is known.
|
In particular, parts of the design of the Reflection API make no sense unless this feature is known.
|
||||||
|
|
||||||
With a multifile assembly, there’s always one master file that represents the assembly. This will be a PE file, and it contains a particular element of the metadata called the **assembly manifest**. This is not to be confused with the Win32-style manifest that most executables contain.
|
With a multifile assembly, there’s always one master file that represents the assembly. This will be a PE file, and it contains a particular element of the metadata called the **assembly manifest**.
|
||||||
|
This is not to be confused with the Win32-style manifest that most executables contain.
|
||||||
The assembly manifest is just a description of what’s in the assembly, including a list of any external modules or other external files; in a multimodule assembly, the manifest describes which types are defined in which files.
|
The assembly manifest is just a description of what’s in the assembly, including a list of any external modules or other external files; in a multimodule assembly, the manifest describes which types are defined in which files.
|
||||||
|
|
||||||
### Assembly Resolution
|
### Assembly Resolution
|
||||||
|
@ -2348,7 +2366,8 @@ Assembly names always include a **version number**. There are also some optional
|
||||||
If an assembly’s name includes a public key token, it is said to be a **strong name**. Microsoft advises that any .NET component that is published for shared use (e.g: made available via NuGet) should have a strong name.
|
If an assembly’s name includes a public key token, it is said to be a **strong name**. Microsoft advises that any .NET component that is published for shared use (e.g: made available via NuGet) should have a strong name.
|
||||||
|
|
||||||
As the terminology suggests, an assembly name’s public key token has a connection with cryptography. It is the hexadecimal representation of a 64-bit hash of a publickey.
|
As the terminology suggests, an assembly name’s public key token has a connection with cryptography. It is the hexadecimal representation of a 64-bit hash of a publickey.
|
||||||
Strongly named assemblies are required to contain a copy of the full public keyfrom which the hash was generated. The assembly file format also provides space fora digital signature, generated with the corresponding private key.
|
Strongly named assemblies are required to contain a copy of the full public keyfrom which the hash was generated.
|
||||||
|
The assembly file format also provides space fora digital signature, generated with the corresponding private key.
|
||||||
|
|
||||||
The uniqueness of a strong name relies on the fact that key generation systems use cryptographically secure random-number generators, and the chances of two people generating two key pairs with the same public key token are vanishingly small.
|
The uniqueness of a strong name relies on the fact that key generation systems use cryptographically secure random-number generators, and the chances of two people generating two key pairs with the same public key token are vanishingly small.
|
||||||
The assurance that the assembly has ot been tampered with comes from the fact thatastrongly named assembly must be signed, and only someone in possession of the private key can generate a valid signature. Any attempt to modify the assembly aftersigning it will invalidate the signature.
|
The assurance that the assembly has ot been tampered with comes from the fact thatastrongly named assembly must be signed, and only someone in possession of the private key can generate a valid signature. Any attempt to modify the assembly aftersigning it will invalidate the signature.
|
||||||
|
@ -2449,7 +2468,7 @@ The only things that should comebefore assembly-level attributes are whichever u
|
||||||
[module : AttrName]
|
[module : AttrName]
|
||||||
```
|
```
|
||||||
|
|
||||||
Methods’ return values can be annotated, and this also requires qualification, becaus ereturn value attributes go in front of the method, the same place as attributes that apply to the method itself.
|
Methods’ return values can be annotated, and this also requires qualification, because return value attributes go in front of the method, the same place as attributes that apply to the method itself.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
[AttrName]
|
[AttrName]
|
||||||
|
@ -2499,10 +2518,11 @@ public interface ICustomAttributeProvider
|
||||||
|
|
||||||
## Files & Streams
|
## Files & Streams
|
||||||
|
|
||||||
A .NET **stream** is simply a _sequence of bytes_. That makes a stream a useful abstraction for many commonly encountered features such as a file on disk, or the body of an HTTPresponse.
|
A .NET **stream** is simply a _sequence of bytes_. That makes a stream a useful abstraction for many commonly encountered features such as a file on disk, or the body of an HTTP response.
|
||||||
A console application uses streams to represent its input and output.
|
A console application uses streams to represent its input and output.
|
||||||
|
|
||||||
The `Stream` class is defined in the `System.IO` namespace. It is an abstract base class, with concrete derived types such as `FileStream` or `GZipStream` representing particular kinds of streams.
|
The `Stream` class is defined in the `System.IO` namespace.
|
||||||
|
It is an abstract base class, with concrete derived types such as `FileStream` or `GZipStream` representing particular kinds of streams.
|
||||||
|
|
||||||
```cs
|
```cs
|
||||||
// The most important members of Stream
|
// The most important members of Stream
|
||||||
|
@ -2548,8 +2568,10 @@ A stream automatically flushes its contents when calling `Dispose`. Flush only w
|
||||||
It is particularly important if there will be extended periods during which the stream isopen but inactive.
|
It is particularly important if there will be extended periods during which the stream isopen but inactive.
|
||||||
|
|
||||||
**NOTE**: When using a `FileStream`, the `Flush` method does not necessarily guarantee that the data being flushed has made it to disk yet. It merely makes the stream pass the data to the OS.
|
**NOTE**: When using a `FileStream`, the `Flush` method does not necessarily guarantee that the data being flushed has made it to disk yet. It merely makes the stream pass the data to the OS.
|
||||||
Before calling `Flush`, the OS hasn’t even seen the data, so if the process terminates suddenly, the data would be lost. After `Flush` has returned, the OS has everything the code has written, so the process could be terminated without loss of data.
|
Before calling `Flush`, the OS hasn’t even seen the data, so if the process terminates suddenly, the data would be lost.
|
||||||
|
After `Flush` has returned, the OS has everything the code has written, so the process could be terminated without loss of data.
|
||||||
However, the OS may perform additional buffering of its own, so if the power fails before the OS gets around to writing everything to disk, the data will still be lost.
|
However, the OS may perform additional buffering of its own, so if the power fails before the OS gets around to writing everything to disk, the data will still be lost.
|
||||||
|
|
||||||
To guarantee that data has been written persistently (rather than merely ensuring that it has been handed it to the OS), use either the `WriteThrough` flag, or call the `Flush` overload that takes a bool, passing `true` to force flushing to disk.
|
To guarantee that data has been written persistently (rather than merely ensuring that it has been handed it to the OS), use either the `WriteThrough` flag, or call the `Flush` overload that takes a bool, passing `true` to force flushing to disk.
|
||||||
|
|
||||||
### [StreamReader][stream_reader_docs] & [StreamWriter][stream_writer_docs] (Text Files)
|
### [StreamReader][stream_reader_docs] & [StreamWriter][stream_writer_docs] (Text Files)
|
||||||
|
@ -2598,7 +2620,7 @@ catch (Exception e)
|
||||||
### StringReader & StringWriter
|
### StringReader & StringWriter
|
||||||
|
|
||||||
The `StringReader` and `StringWriter` classes serve a similar purpose to `MemoryStream`: they are useful when working with an API that requires either a `TextReader` or `TextWriter` (abstract text streams), but you want to work entirely in memory.
|
The `StringReader` and `StringWriter` classes serve a similar purpose to `MemoryStream`: they are useful when working with an API that requires either a `TextReader` or `TextWriter` (abstract text streams), but you want to work entirely in memory.
|
||||||
Whereas `MemoryStream` presents a Stream API on top of a `byte[]` array, StringReader wraps a string as a `TextReader`, while `StringWriter` presents a `TextWriter` API on top of a `StringBuilder`.
|
Whereas `MemoryStream` presents a Stream API on top of a `byte[]` array, `StringReader` wraps a string as a `TextReader`, while `StringWriter` presents a `TextWriter` API on top of a `StringBuilder`.
|
||||||
|
|
||||||
## Files & Directories
|
## Files & Directories
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue