Skip to content

Instantly share code, notes, and snippets.

@RajaniCode
Last active August 17, 2024 00:15
Show Gist options
  • Select an option

  • Save RajaniCode/33e7bb0305578371278702eef82c21a6 to your computer and use it in GitHub Desktop.

Select an option

Save RajaniCode/33e7bb0305578371278702eef82c21a6 to your computer and use it in GitHub Desktop.
CS8
// CS 8
/*
1. Readonly members
2. Default interface methods
3. Pattern matching enhancements:
// Switch expressions
// Property patterns
// Tuple patterns
// Positional patterns
4. Using declarations
5. Static local functions
6. Disposable ref structs
7. Nullable reference types
8. Asynchronous streams
9. Indices and ranges
10. Null-coalescing assignment
11. Unmanaged constructed types
12. Stackalloc in nested expressions
13. Enhancement of interpolated verbatim strings
14. Interface with member access specifiers and static members including fields
15. ! (null-forgiving) operator
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
struct Point
{
public double X { get; set; }
public double Y { get; set; }
// public double Distance => Math.Sqrt(X * X + Y * Y);
/*
public override string ToString() =>
$"({X}, {Y}) is {Distance} from the origin";
*/
// 1. Readonly members
public readonly void Print() => Console.WriteLine("1. Readonly members");
// Like most structs, the ToString() method doesn't modify state.
// You could indicate that by adding the readonly modifier to the declaration of ToString():
public readonly override string ToString() =>
$"({X}, {Y}) is {Distance} from the origin";
// The preceding change generates a compiler warning, because ToString accesses the Distance property, which isn't marked readonly:
// The compiler warns you when it needs to create a defensive copy.
// The Distance property doesn't change state, so you can fix this warning by adding the readonly modifier to the declaration:
public readonly double Distance => Math.Sqrt(X * X + Y * Y);
// Notice that the readonly modifier is necessary on a read-only property.
// The compiler doesn't assume get accessors don't modify state; you must declare readonly explicitly.
// Auto-implemented properties are an exception; the compiler will treat all auto-implemented getters as readonly, so here there's no need to add the readonly modifier to the X and Y properties.
// The compiler does enforce the rule that readonly members don't modify state.
// The following method won't compile unless you remove the readonly modifier:
// public readonly void Translate(int xOffset, int yOffset)
public void Translate(int xOffset, int yOffset)
{
X += xOffset;
Y += yOffset;
}
// This feature lets you specify your design intent so the compiler can enforce it, and make optimizations based on that intent.
}
interface ILogger
{
void Info(string message);
void Error(string message);
// 2. Default interface methods
void Warn(string message)
{
Debug.WriteLine(message);
}
}
class DefaultInterfaceMethods : ILogger
{
public void Info(string message)
{
Debug.WriteLine(message);
}
public void Error(string message)
{
Debug.WriteLine(message);
}
public void Print()
{
Console.WriteLine("2. Default interface methods");
ILogger logger = new DefaultInterfaceMethods();
logger.Warn("This is warning from default interface method");
}
}
enum Rainbow
{
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
}
class RGBColor
{
public int R;
public int G;
public int B;
public RGBColor(int R, int G, int B)
{
this.R = R;
this.G = G;
this.B = B;
}
}
class Patterns
{
// 3. Pattern matching enhancements:
// Switch expressions
// If your application defined an RGBColor type that is constructed from the R, G and B components, you could convert a Rainbow value to its RGB values using the following method containing a switch expression:
private RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};
// There are several syntax improvements here:
// The variable comes before the switch keyword. The different order makes it visually easy to distinguish the switch expression from the switch statement.
// The case and : elements are replaced with =>. It's more concise and intuitive.
// The default case is replaced with a _ discard.
// The bodies are expressions, not statements.
// Contrast that with the equivalent code using the classic switch statement:
private RGBColor FromRainbowClassic(Rainbow colorBand)
{
switch (colorBand)
{
case Rainbow.Red:
return new RGBColor(0xFF, 0x00, 0x00);
case Rainbow.Orange:
return new RGBColor(0xFF, 0x7F, 0x00);
case Rainbow.Yellow:
return new RGBColor(0xFF, 0xFF, 0x00);
case Rainbow.Green:
return new RGBColor(0x00, 0xFF, 0x00);
case Rainbow.Blue:
return new RGBColor(0x00, 0x00, 0xFF);
case Rainbow.Indigo:
return new RGBColor(0x4B, 0x00, 0x82);
case Rainbow.Violet:
return new RGBColor(0x94, 0x00, 0xD3);
default:
throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand));
};
}
// 3. Pattern matching enhancements:
// Property patterns
private decimal ComputeSalesTax(Address location, decimal salePrice) =>
location switch
{
{ State: "WA" } => salePrice * 0.06M,
{ State: "MN" } => salePrice * 0.75M,
{ State: "MI" } => salePrice * 0.05M,
// other cases removed for brevity...
_ => 0M
};
// 3. Pattern matching enhancements:
// Tuple patterns
private string RockPaperScissors(string first, string second) =>
(first, second) switch
{
("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie"
};
// 3. Pattern matching enhancements:
// Positional patterns
private Quadrant GetQuadrant(Point2 point) =>
point switch
{
(0, 0) => Quadrant.Origin,
var (x, y) when x > 0 && y > 0 => Quadrant.One,
var (x, y) when x < 0 && y > 0 => Quadrant.Two,
var (x, y) when x < 0 && y < 0 => Quadrant.Three,
var (x, y) when x > 0 && y < 0 => Quadrant.Four,
var (_, _) => Quadrant.OnBorder,
_ => Quadrant.Unknown
};
public void Print()
{
Console.WriteLine("3. Pattern matching enhancements: Switch expressions");
RGBColor rgb = FromRainbow(Rainbow.Red);
Console.WriteLine("R:{0}, G:{1}, B:{2}", rgb.R, rgb.G, rgb.B);
Console.WriteLine("3. Pattern matching enhancements: Property patterns");
Address location = new Address();
location.State = "WA";
decimal salesTax = ComputeSalesTax(location, 100);
Console.WriteLine("Sales Tax = {0}", salesTax);
Console.WriteLine("3. Pattern matching enhancements: Tuple patterns");
string message = RockPaperScissors("paper", "rock");
Console.WriteLine(message);
Console.WriteLine("3. Pattern matching enhancements: Positional patterns");
Point2 point = new Point2(-1, -2);
Quadrant quad = GetQuadrant(point);
Console.WriteLine("Quadrant:{0}", quad);
}
}
class Address
{
#nullable enable
public string? State
{
get;
set;
}
#nullable disable
}
class Point2
{
public int X { get; }
public int Y { get; }
public Point2(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) =>
(x, y) = (X, Y);
}
enum Quadrant
{
Unknown,
Origin,
One,
Two,
Three,
Four,
OnBorder
}
class UsingDeclarations
{
public int WriteLinesToFile(IEnumerable<string> lines)
{
// 4. Using declarations
// A using declaration is a variable declaration preceded by the using keyword. It tells the compiler that the variable being declared should be disposed at the end of the enclosing scope. For example, consider the following code that writes a text file:
Console.WriteLine("4. Using declarations");
using var file = new System.IO.StreamWriter("WriteLines.txt");
// Notice how we declare skippedLines after the using statement.
int skippedLines = 0;
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
// Notice how skippedLines is in scope here.
return skippedLines;
// file is disposed here
}
// In the preceding example, the file is disposed when the closing brace for the method is reached. That's the end of the scope in which file is declared. The preceding code is equivalent to the following code that uses the classic using statement:
public int WriteLinesToFileClassic(IEnumerable<string> lines)
{
// We must declare the variable outside of the using block
// so that it is in scope to be returned.
int skippedLines = 0;
using (var file = new System.IO.StreamWriter("WriteLines.txt"))
{
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
} // file is disposed here
return skippedLines;
}
// In the preceding example, the file is disposed when the closing brace associated with the using statement is reached.
// In both cases, the compiler generates the call to Dispose().
// The compiler generates an error if the expression in the using statement isn't disposable.
}
// You can now add the static modifier to local functions to ensure that local function doesn't capture (reference) any variables from the enclosing scope.
// Doing so generates CS8421, "A static local function can't contain a reference to <variable>."
// Consider the following code.
// The local function LocalFunction accesses the variable y, declared in the enclosing scope (the method M).
// Therefore, LocalFunction can't be declared with the static modifier:
class StaticLocalFunctions
{
public int M()
{
int y;
LocalFunction();
return y;
void LocalFunction() => y = 0;
}
// 5. Static local functions
// The following code contains a static local function. It can be static because it doesn't access any variables in the enclosing scope:
public int F()
{
int y = 5;
int x = 7;
Console.WriteLine("5. Static local functions");
return Add(x, y);
static int Add(int left, int right) => left + right;
}
}
// 6. Disposable ref structs
// When you compile this program, you would observe a compilation error CS8343: 'Author': ref structs cannot implement interfaces
// ref struct Author : IDisposable
// From C# 8 onwards, ref struct can be disposed without the need of implementing the IDisposable interface.
// All you need to do is add a public Dispose method to the ref struct.
// This would ensure that an instance of thr struct is consumed by using statements as below:
ref struct Author
{
public void Dispose()
{
Console.WriteLine("6. Disposable ref structs");
}
}
class NullableReferenceTypes
{
public void Print()
{
// 7. Nullable reference types
Console.WriteLine("7. Nullable reference types");
/*
//.csproj
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
*/
#nullable enable
string? nullableTeference = null;
#nullable restore
Console.WriteLine($"{nullableTeference = ((new Random().Next(1, 11) % 2 == 0) ? "Nullable string" : null)}");
}
}
class AsynchronousStreams
{
// 8. Asynchronous streams
// A method that returns an asynchronous stream has three properties:
// It's declared with the async modifier.
// It returns an IAsyncEnumerable<T>.
// The method contains yield return statements to return successive elements in the asynchronous stream.
private async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
}
public async Task AsyncPrint()
{
Console.WriteLine("8. Asynchronous streams");
// Consuming an asynchronous stream requires you to add the await keyword before the foreach keyword when you enumerate the elements of the stream.
// Adding the await keyword requires the method that enumerates the asynchronous stream to be declared with the async modifier and to return a type allowed for an async method.
await foreach (var number in GenerateSequence())
{
Console.Write(number + " ");
}
Console.WriteLine("");
}
}
class IndicesAndRanges
{
public void Print()
{
var alphabet = new string[]
{
// index // ^index
"A", // 0 // ^26
"B", // 1 // ^25
"C", // 2 // ^24
"D", // 3 // ^23
"E", // 4 // ^22
"F", // 5 // ^21
"G", // 6 // ^20
"H", // 7 // ^19
"I", // 8 // ^18
"J", // 9 // ^17
"K", // 10 // ^16
"L", // 11 // ^15
"M", // 12 // ^14
"N", // 13 // ^13
"O", // 14 // ^12
"P", // 15 // ^11
"Q", // 16 // ^10
"R", // 17 // ^9
"S", // 18 // ^8
"T", // 19 // ^7
"U", // 20 // ^6
"V", // 21 // ^5
"W", // 22 // ^4
"X", // 23 // ^3
"Y", // 24 // ^2
"Z" // 25 // ^1
// 26 (or alphabet.Length)
};
// 9. Indices and ranges
Console.WriteLine("9. Indices and ranges");
Console.WriteLine("Array.ForEach:");
Array.ForEach(alphabet[0..5], x => Console.Write(x + " "));
Console.WriteLine();
Console.WriteLine("ToList().ForEachh:");
alphabet[0..5].ToList().ForEach(x => Console.Write(x + " "));
Console.WriteLine();
Console.WriteLine("ToList().GetEnumerator():");
IEnumerator<string> enumerate = alphabet[0..5].ToList().GetEnumerator();
while (enumerate.MoveNext())
{
Console.Write(enumerate.Current);
Console.Write(" ");
};
Console.WriteLine();
Console.WriteLine($"alphabet[0..5].GetLowerBound(0): {alphabet[0..5].GetLowerBound(0)}");
Console.WriteLine($"alphabet[0..5].GetUpperBound(0): {alphabet[0..5].GetUpperBound(0)}");
Console.WriteLine($"The first alphabet: alphabet[0]: {alphabet[0]}");
Console.WriteLine($"The first alphabet: alphabet[^26]: {alphabet[^26]}");
Console.WriteLine($"The last alphabet: alphabet[25]: {alphabet[25]}");
Console.WriteLine($"The last alphabet: alphabet[^1]: {alphabet[^1]}");
Console.WriteLine($"alphabet[0..5]: {string.Join(", ", alphabet[0..5])}");
Console.WriteLine($"alphabet[1..4]: {string.Join(", ", alphabet[1..4])}");
Console.WriteLine($"alphabet[^5..^0]: {string.Join(", ", alphabet[^5..^0])}");
Console.WriteLine($"alphabet[^4..^1]: {string.Join(", ", alphabet[^4..^1])}");
Console.WriteLine($"alphabet[5..]: {string.Join(", ", alphabet[5..])}");
Console.WriteLine($"alphabet[..5]: {string.Join(", ", alphabet[..5])}");
Console.WriteLine($"alphabet[..]: {string.Join(", ", alphabet[..])}");
// Range as variable:
Range rangeDotDot = ..;
Console.WriteLine($"Range as variable (Range rangeDotDot = ..) in alphabet[rangeDotDot]: {string.Join(", ", alphabet[rangeDotDot])}");
string alphanumeric = "Indices and ranges";
Console.WriteLine($"Substring \"and\" in \"9. Indices and ranges\": alphanumeric[^10..^7]: {alphanumeric[^10..^7]}");
Console.WriteLine($"Substring \"World\" from \"Hello World!\"[^6..^1]: {"Hello World!"[^6..^1]}");
}
}
class NullCoalescingAssignment
{
#nullable enable
public void Print()
{
// 10. Null-coalescing assignment
// C# 8.0 introduces the null-coalescing assignment operator ??=.
// You can use the ??= operator to assign the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null.
List<int>? numbers = null;
int? i = null;
numbers ??= new List<int>();
Console.WriteLine("10. Null-coalescing assignment");
numbers.Add(i ??= 17);
numbers.Add(i ??= 20);
Console.WriteLine(string.Join(" ", numbers)); // output: 17 17
Console.WriteLine(i); // output: 17
int? j = null;
numbers.Add(j ??= 27);
numbers.Add(j ??= 30);
Console.WriteLine(string.Join(" ", numbers)); // output: 17 17 27 27
Console.WriteLine(j); // output: 27
}
#nullable disable
}
// 11. Unmanaged constructed types
// A type is an unmanaged type if it's any of the following types:
// sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool
// Any enum type
// Any pointer type
// Any user-defined struct type that contains fields of unmanaged types only and, in C# 7.3 and earlier, is not a constructed type (a type that includes at least one type argument)
// Beginning with C# 7.3, you can use the unmanaged constraint to specify that a type parameter is a non-pointer unmanaged type.
// Beginning with C# 8.0, a constructed struct type that contains fields of unmanaged types only is also unmanaged, as the following example shows:
struct Coords<T>
{
public T X;
public T Y;
public Coords(T x, T y)
{
X = x;
Y = y;
}
}
// A generic struct may be the source of both unmanaged and not unmanaged constructed types.
// The preceding example defines a generic struct Coords<T> and presents the examples of unmanaged constructed types.
// The example of not an unmanaged type is Coords<object>.
// It's not unmanaged because it has the fields of the object type, which is not unmanaged.
// If you want all constructed types to be unmanaged types, use the unmanaged constraint in the definition of a generic struct:
struct CoordsUnmanaged<T> where T : unmanaged
{
public T X;
public T Y;
public CoordsUnmanaged(T x, T y)
{
X = x;
Y = y;
}
}
class UnmanagedTypes
{
public void Print()
{
Console.WriteLine("11. Unmanaged constructed types");
DisplaySize<Coords<int>>();
DisplaySize<Coords<double>>();
}
/*
//.csproj
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
*/
private unsafe void DisplaySize<T>() where T : unmanaged
{
Console.WriteLine($"{typeof(T)} is unmanaged and its size is {sizeof(T)} bytes");
}
}
class StackallocInNestedExpressions
{
public void Print()
{
// 12. Stackalloc in nested expressions
// Starting with C# 8.0, if the result of a stackalloc expression is of the System.Span<T> or System.ReadOnlySpan<T> type, you can use the stackalloc expression in other expressions:
Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine("12. Stackalloc in nested expressions");
var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6, 8 });
Console.WriteLine(ind); // output: 1
}
}
class EnhancementOfInterpolatedVerbatimStrings
{
public void Print()
{
// 13. Enhancement of interpolated verbatim strings
// Order of the $ and @ tokens in interpolated verbatim strings can be any: both $@"..." and @$"..." are valid interpolated verbatim strings.
// In earlier CS versions, the $ token must appear before the @ token.
string name = "Sharp";
var date = DateTime.Now;
Console.WriteLine("13. Enhancement of interpolated verbatim strings");
string s = @$"{name} said, ""Today is {date.DayOfWeek}, it's {date:HH:mm} now.""";
Console.WriteLine(s);
}
}
// 14. Interface with member access specifiers and static members including fields
// Different access modifiers are also enabled
// The additional fields are private, the new method is public
// Any of the modifiers are allowed on interface members
interface IAccessInstancePropertiesMethods
{
private string Garply => "Private Instance Property";
protected string Waldo { get; set; }
internal string Fred { get; set; }
protected internal string Plugh { get; set; }
private protected string Xyzzy { get; set; }
public string Thud { get; set; }
string Wibble { get; set; } // default access modifier in interface is public
private void Wobble() { }
protected void Wubble() { }
internal void Flob() { }
protected internal void Hoge() { }
private protected void Fuga() { }
public void Hogera() { }
void Hogehoge() { } // default access modifier in interface is public
}
// 14. Interface with member access specifiers and static members including fields
// Interfaces can now include static members, including fields, properties, and methods.
interface IAccessStaticFieldsPropertiesMethods
{
private static string Foo = "14. Interface with member access specifiers and static members including fields";
protected static string Bar = "Bar";
internal static string Baz = "Baz";
protected internal static string Qux = "Qux";
private protected static string Quux = "Quux";
public static string Corge = "Corge";
static string Grault => Foo; // default access modifier in interface is public
private static string Garply { get; set; }
protected static string Waldo { get; set; }
internal static string Fred { get; set; }
protected static internal string Plugh { get; set; }
private static protected string Xyzzy { get; set; }
public static string Thud { get; set; }
static string Wibble { get; set; } // default access modifier in interface is public
private static void Wobble() { }
protected static void Wubble() { }
internal static void Flob() { }
protected static internal void Hoge() { }
private static protected void Fuga() { }
public static void Hogera() { }
static void Hogehoge() { } // default access modifier in interface is public
}
// 15. ! (null-forgiving) operator
class NullForgiving
{
// warning CS8618: Non-nullable property 'Property' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public NullForgiving() { }
public NullForgiving(string property) => Property = property; // ?? throw new ArgumentNullException(nameof(property));
#nullable enable
public string? Property { get; }
public void Print()
{
NullForgiving? result = Search("Without ! (null-forgiving) operator compiler generates warning CS8602: Dereference of a possibly null reference");
if (IsNotNull(result))
{
// warning CS8602: Dereference of a possibly null reference.
// Search method returns nullable
// ! (null-forgiving) operator
Console.WriteLine("15. ! (null-forgiving) operator");
// Console.WriteLine($"Search Result: {result.Property}");
Console.WriteLine($"Use: result!.Property instead of result.Property: : {result!.Property}");
}
result = Search("No warning");
if (IsNotNullWhen(result))
{
Console.WriteLine("Use the NotNullWhen attribute to inform the compiler that an argument of the IsNotNullWhen method can't be null when the method returns true");
// No warning
Console.WriteLine($"Search Result: {result.Property}");
}
}
private bool IsNotNull(NullForgiving? result) => result != null && result.Property != null;
private bool IsNotNullWhen([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] NullForgiving? result) => result != null && result.Property != null;
private static NullForgiving? Search(string property)
{
return new NullForgiving(property);
}
#nullable disable
}
class EnvironmentProperties
{
public void Print()
{
Console.WriteLine($"Environment.OSVersion: {Environment.OSVersion}");
Console.WriteLine($"Environment.OSVersion.Platform: {Environment.OSVersion.Platform}");
Console.WriteLine($"Environment.OSVersion.Version: {Environment.OSVersion.Version}");
Console.WriteLine($"Environment.OSVersion.VersionString: {Environment.OSVersion.VersionString}");
Console.WriteLine($"Environment.OSVersion.Version.Major: {Environment.OSVersion.Version.Major}");
Console.WriteLine($"Environment.OSVersion.Version.Minor: {Environment.OSVersion.Version.Minor}");
Console.WriteLine($"Environment.OSVersion.Platform == System.PlatformID.Win32NT: {Environment.OSVersion.Platform == System.PlatformID.Win32NT}");
Console.WriteLine($"Environment.OSVersion.Platform == System.PlatformID.Unix: {Environment.OSVersion.Platform == System.PlatformID.Unix}");
// Mono JIT compiler version 6.12.0.206 'PlatformID' does not contain a definition for 'Other'
// Console.WriteLine($"Environment.OSVersion.Platform == System.PlatformID.Other: {Environment.OSVersion.Platform == System.PlatformID.Other}");
// System.PlatformID.Win32NT
// Console.WriteLine($"Environment.OSVersion.ServicePack: {Environment.OSVersion.ServicePack}");
// Environment.Version property returns the .NET runtime version for .NET 5+ and .NET Core 3.x
// Not recommend for .NET Framework 4.5+
Console.WriteLine($"Environment.Version: {Environment.Version}");
// <-- Keep this information secure! -->
// Console.WriteLine($"Environment.UserName: {Environment.UserName}");
// <-- Keep this information secure! -->
// Console.WriteLine($"Environment.MachineName: {Environment.MachineName}");
// <-- Keep this information secure! -->
// Console.WriteLine($"Environment.UserDomainName: {Environment.UserDomainName}");
Console.WriteLine($"Environment.Is64BitOperatingSystem: {Environment.Is64BitOperatingSystem}");
Console.WriteLine($"Environment.Is64BitProcess: {Environment.Is64BitProcess}");
// <-- Keep this information secure! -->
// Console.WriteLine("CurrentDirectory: {0}", Environment.CurrentDirectory);
// <-- Keep this information secure! -->
// Console.WriteLine("SystemDirectory: {0}", Environment.SystemDirectory);
// RuntimeInformation.FrameworkDescription property gets the name of the .NET installation on which an app is running
// .NET 5+ and .NET Core 3.x // .NET Framework 4.7.1+ // Mono 5.10.1+
Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}");
Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture: {System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture}");
Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.OSArchitecture: {System.Runtime.InteropServices.RuntimeInformation.OSArchitecture}");
Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.OSDescription): {System.Runtime.InteropServices.RuntimeInformation.OSDescription}");
// Mono JIT compiler version 6.12.0.206 'RuntimeInformation' does not contain a definition for 'RuntimeIdentifier'
// Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier: {System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier}");
// <-- Keep this information secure! -->
#if comments
Console.WriteLine("Environment Variables:");
foreach (System.Collections.DictionaryEntry de in Environment.GetEnvironmentVariables())
{
Console.WriteLine("{0} = {1}", de.Key, de.Value);
}
#endif
}
}
class Program
{
static void Main()
{
var propertiesEnvironment = new EnvironmentProperties();
propertiesEnvironment.Print();
Console.WriteLine();
// 1. Readonly members
Point pnt = new Point();
pnt.Print();
Console.WriteLine();
// 2. Default interface methods
DefaultInterfaceMethods defaultInterfaceMethod = new DefaultInterfaceMethods();
defaultInterfaceMethod.Print();
Console.WriteLine();
// 3. Pattern matching enhancements
Patterns pattern = new Patterns();
pattern.Print();
Console.WriteLine();
// 4. Using declarations
UsingDeclarations usingDeclaration = new UsingDeclarations();
IEnumerable<string> lines = new string[] { "Apple", "Orange", "Banana" };
usingDeclaration.WriteLinesToFile(lines);
Console.WriteLine();
// 5. Static local functions
StaticLocalFunctions staticLocalFunction = new StaticLocalFunctions();
staticLocalFunction.F();
Console.WriteLine();
// 6. Disposable ref structs
Author athr;
athr.Dispose();
Console.WriteLine();
// 7. Nullable reference types
NullableReferenceTypes nullableReferenceType = new NullableReferenceTypes();
nullableReferenceType.Print();
Console.WriteLine();
// 8. Asynchronous streams
AsynchronousStreams asyncStreams = new AsynchronousStreams();
Task asyncTask = asyncStreams.AsyncPrint();
asyncTask.Wait();
Console.WriteLine();
// 9. Indices and ranges
IndicesAndRanges indicesRanges = new IndicesAndRanges();
indicesRanges.Print();
Console.WriteLine();
// 10. Null-coalescing assignment
NullCoalescingAssignment nullCoalescingAssign = new NullCoalescingAssignment();
nullCoalescingAssign.Print();
Console.WriteLine();
// 11. Unmanaged constructed types
UnmanagedTypes unmanagedType = new UnmanagedTypes();
unmanagedType.Print();
Console.WriteLine();
// 12. Stackalloc in nested expressions
StackallocInNestedExpressions stackallocInNestedExpress = new StackallocInNestedExpressions();
stackallocInNestedExpress.Print();
Console.WriteLine();
// 13. Enhancement of interpolated verbatim strings
EnhancementOfInterpolatedVerbatimStrings interpolatedVerbatimStrings = new EnhancementOfInterpolatedVerbatimStrings();
interpolatedVerbatimStrings.Print();
Console.WriteLine();
// 14. Interface with member access specifiers and static members including fields
Console.WriteLine(IAccessStaticFieldsPropertiesMethods.Grault);
Console.WriteLine();
// 15. ! (null-forgiving) operator
// ! (null-forgiving) operator
new NullForgiving().Print();
// ?? throw new ArgumentNullException(nameof(property));
// var forgivingNull = new NullForgiving(null!);
}
}
// NB
// CS 8 Nullable reference type
// csc/mcs #nullable enable // #nullable disable
// dotnet // <Nullable>enable</Nullable> in .csproj
// % dotnet run --configuration Debug
// Or
// % dotnet run --configuration Release
// Output
/*
Environment.OSVersion: Unix 23.4.0.0
Environment.OSVersion.Platform: Unix
Environment.OSVersion.Version: 23.4.0.0
Environment.OSVersion.VersionString: Unix 23.4.0.0
Environment.OSVersion.Version.Major: 23
Environment.OSVersion.Version.Minor: 4
Environment.OSVersion.Platform == System.PlatformID.Win32NT: False
Environment.OSVersion.Platform == System.PlatformID.Unix: True
Environment.Version: 3.1.32
Environment.Is64BitOperatingSystem: True
Environment.Is64BitProcess: True
System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription: .NET Core 3.1.32
System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture: X64
System.Runtime.InteropServices.RuntimeInformation.OSArchitecture: X64
System.Runtime.InteropServices.RuntimeInformation.OSDescription): Darwin 23.4.0 Darwin Kernel Version 23.4.0: Fri Mar 15 00:10:42 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T6000
1. Readonly members
2. Default interface methods
3. Pattern matching enhancements: Switch expressions
R:255, G:0, B:0
3. Pattern matching enhancements: Property patterns
Sales Tax = 6.00
3. Pattern matching enhancements: Tuple patterns
paper covers rock. Paper wins.
3. Pattern matching enhancements: Positional patterns
Quadrant:Three
4. Using declarations
5. Static local functions
6. Disposable ref structs
7. Nullable reference types
Nullable string
8. Asynchronous streams
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
9. Indices and ranges
Array.ForEach:
A B C D E
ToList().ForEachh:
A B C D E
ToList().GetEnumerator():
A B C D E
alphabet[0..5].GetLowerBound(0): 0
alphabet[0..5].GetUpperBound(0): 4
The first alphabet: alphabet[0]: A
The first alphabet: alphabet[^26]: A
The last alphabet: alphabet[25]: Z
The last alphabet: alphabet[^1]: Z
alphabet[0..5]: A, B, C, D, E
alphabet[1..4]: B, C, D
alphabet[^5..^0]: V, W, X, Y, Z
alphabet[^4..^1]: W, X, Y
alphabet[5..]: F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
alphabet[..5]: A, B, C, D, E
alphabet[..]: A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
Range as variable (Range rangeDotDot = ..) in alphabet[rangeDotDot]: A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
Substring "and" in "9. Indices and ranges": alphanumeric[^10..^7]: and
Substring "World" from "Hello World!"[^6..^1]: World
10. Null-coalescing assignment
17 17
17
17 17 27 27
27
11. Unmanaged constructed types
Coords`1[System.Int32] is unmanaged and its size is 8 bytes
Coords`1[System.Double] is unmanaged and its size is 16 bytes
12. Stackalloc in nested expressions
1
13. Enhancement of interpolated verbatim strings
Sharp said, "Today is Friday, it's 13:29 now."
14. Interface with member access specifiers and static members including fields
15. ! (null-forgiving) operator
Use: result!.Property instead of result.Property: : Without ! (null-forgiving) operator compiler generates warning CS8602: Dereference of a possibly null reference
Use the NotNullWhen attribute to inform the compiler that an argument of the IsNotNullWhen method can't be null when the method returns true
Search Result: No warning
*/
// Credit:
/*
https://dotnet.microsoft.com/
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment