Skip to content

Instantly share code, notes, and snippets.

@RajaniCode
Last active November 1, 2024 05:11
Show Gist options
  • Save RajaniCode/cc120aa9164a46d0ae86b8a78b7f7731 to your computer and use it in GitHub Desktop.
Save RajaniCode/cc120aa9164a46d0ae86b8a78b7f7731 to your computer and use it in GitHub Desktop.
CS12.cs
// CS 12
/*
1. Primary constructors
2. Collection expressions
3. ref readonly parameters
4. Default lambda parameters
5. Alias any type
6. Inline arrays
7. Experimental attribute
8. Interceptors
*/
/*************************************************************************************************************************/
// 5. Alias any type
/*************************************************************************************************************************/
global using File.Scoped.Namespace.Global.Alias.Any.Type;
global using File.Scoped.Namespace.Global.Alias.Any.Type.Extensions;
global using Horse = System.Collections.Generic.IEnumerable<File.Scoped.Namespace.Global.Alias.Any.Type.Vehicle>;
global using Stealth = System.Collections.Generic.IEnumerable<File.Scoped.Namespace.Global.Alias.Any.Type.Extensions.Jet>;
global using Air = System.Collections.Generic.IEnumerable<File.Scoped.Namespace.Global.Alias.Any.Type.Extensions.Aircraft>;
// static Alias
// A 'using static' directive can only be applied to types
global using static System.Array;
// Custom Alias
global using Tuple = (dynamic T1, dynamic T2);
// Using alias cannot be a nullable reference type
// using NRSA = System.Array?;
// using NRS = string?;
// System.Collections.Generic.List is not nullable type
// using GS = System.Collections.Generic.List<string?>;
// Nullable value type
using NVT = int?;
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("Environment Properties");
/*************************************************************************************************************************/
EnvironmentProperties propertiesEnvironment = new();
propertiesEnvironment.Print();
Console.WriteLine();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("1. Primary constructors");
/*************************************************************************************************************************/
PrimaryConstructors constructorsPrimary = new("A", "B");
Console.WriteLine(constructorsPrimary);
Console.WriteLine( new PrimaryConstructors() );
Console.WriteLine( new PrimaryConStruct("C") );
Console.WriteLine( new PrimaryConStruct("E").InstanceFieldInStruct );
Console.WriteLine($"IsPropertyGenerated for record class: {new RecordClass(true).IsPropertyGenerated}");
Console.WriteLine($"IsPropertyGenerated for record default class: {new RecordDefraultClass(true).IsPropertyGenerated}");
Console.WriteLine($"IsPropertyGenerated for record struct: {new RecordStruct(true).IsPropertyGenerated}");
// error CS1061: 'NonrecordClass' does not contain a definition for 'IsPropertyGenerated' and no accessible extension method 'IsPropertyGenerated' accepting a first argument of type 'NonrecordClass' could be found
// Console.WriteLine($"IsPropertyGenerated for Nonrecord class: {new NonrecordClass(true).IsPropertyGenerated}");
// error CS1061: 'NonrecordStruct' does not contain a definition for 'IsPropertyGenerated' and no accessible extension method 'IsPropertyGenerated' accepting a first argument of type 'NonrecordStruct'
// Console.WriteLine($"IsPropertyGenerated for Nonrecord struct: {new NonrecordStruct(true).IsPropertyGenerated}");
Console.WriteLine();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("2. Collection expressions");
/*************************************************************************************************************************/
// Collection expressions
// New terse syntax
/*
// Array types
// System.Span<T> and System.ReadOnlySpan<T>
// Types that support collection initializers, such as System.Collections.Generic.List<T>
*/
Console.WriteLine("Terse Syntax Array string[]");
string[] names = ["Alpha", "Beta", "Gamma", "Delta"];
Console.WriteLine( string.Join(", ", names) );
Console.WriteLine("Terse Syntax Array int[]");
int[] numbers = [ 111, 333, 666, 888 ];
Console.WriteLine( string.Join(", ", numbers) );
Console.WriteLine("Terse Syntax List<string>");
List<string> namesList = ["Zeta", "Eta", "Theta", "Iota", "Kappa"];
Console.WriteLine( string.Join(", ", namesList) );
Console.WriteLine("Terse Syntax List<int>");
List<int> numbersList= [ 222, 444, 555, 777 ];
Console.WriteLine( string.Join(", ", numbersList) );
Console.WriteLine("Terse Syntax Span<char>");
// Span<char> asterisk = ['a', 's', 't', 'e', 'r', 'i', 's', 'k']; // Parameters or locals of type 'Span<char>' cannot be declared in async methods or async lambda expressions
// Console.WriteLine( string.Join(", ", asterisk.ToArray()) ); //
Console.WriteLine("Terse Syntax ReadOnlySpan<string>");
// ReadOnlySpan<string> readOnlySpanNames = ["Rock", "*"]; // Parameters or locals of type 'ReadOnlySpan<string>' cannot be declared in async methods or async lambda expressions.
// Console.WriteLine( string.Join(", ", readOnlySpanNames.ToArray()) );
Console.WriteLine("Terse Syntax ReadOnlySpan<string?>");
// ReadOnlySpan<string?> readOnlySpanNullableNames = ["Rock", "*", null, "", string.Empty]; // Parameters or locals of type 'ReadOnlySpan<string?>' cannot be declared in async methods or async lambda expressions.
// Console.WriteLine( string.Join(", ", readOnlySpanNullableNames.ToArray()) );
Console.WriteLine("Terse Syntax ReadOnlySpan<int?>");
// ReadOnlySpan<int?> readOnlySpanNullableNumbers = [ -2, -4, null, -5, -7, null ]; // Parameters or locals of type 'ReadOnlySpan<int?>' cannot be declared in async methods or async lambda expressions.
// Console.WriteLine( string.Join(", ", readOnlySpanNullableNumbers.ToArray()) );
int[][][] terseJagged3D =
[
[
[ 1, 3, 5, 7 ],
[ 11, 33, 55, 77, 99 ],
],
[
[ 2, 4, 6, 8 ],
[ 22, 44, 66, 88 ],
[ 222, 444, 666, 888 ],
[ 2222, 4444, 6666, 8888 ]
],
[
[ 3, 5, 7, 9 ]
],
[
[ -4, -6 ],
[ -44, -66 ],
[ -444, -666 ]
],
[
[ 0 ]
]
];
Console.WriteLine("Terse Syntax Jagged 3D Array Lambda Expression");
// terseJagged3D.ToList().ForEach( x => x.ToList().ForEach( y => y.ToList().ForEach(Console.WriteLine)) );
// terseJagged3D.ToList().ForEach( x => x.ToList().ForEach( y => Console.WriteLine(string.Join(", ", y))) );
/*
terseJagged3D.ToList().ForEach
(
x => x.ToList().ForEach
(
y => y.ToList().ForEach( y => Console.Write( $"{y}, ") )
)
);
Console.WriteLine();
*/
Console.WriteLine($"Terse Syntax Jagged 3D Array Length: {terseJagged3D.Length}" );
Console.WriteLine($"Terse Syntax Jagged 3D Array Count(): {terseJagged3D.Count()}" );
terseJagged3D.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
Console.WriteLine("Terse Syntax Jagged 3D Array Lambda Expression Index");;
terseJagged3D.ToList().ForEach
(
x =>
{
for (int i = 0; i < x.Length; i++)
{
if (i == x.Length - 1)
{
Console.Write(string.Join(", ", x[i]));
}
else
{
Console.Write(string.Join(", ", x[i]) + ", ");
}
}
Console.WriteLine();
}
);
Console.WriteLine("Terse Syntax Jagged 3D Array Lambda Expression string.Join");;
terseJagged3D.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => Console.Write(string.Join(", ", y) + ", ")
);
Console.WriteLine();
}
);
Console.WriteLine("Terse Syntax Jagged 3D Array Lambda Expression IEnumerable");;
// IEnumerable<IEnumerable<IEnumerable<int>>> terseJagged3DEnumerable = terseJagged3D;
IEnumerable<IEnumerable<IEnumerable<int>>> terseJagged3DEnumerable = terseJagged3D.ToList().Select
(
x => x.ToList().Select
(
y => y.ToList().Select( y => y )
)
);
Console.WriteLine($"Terse Syntax Jagged 3D Array IEnumerable Count(): {terseJagged3DEnumerable.Count()}" );
terseJagged3DEnumerable.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
int[][][] jagged3DTerse = [ [[ 1, 3, 5, 7 ]], [[ 2, 4, 6, 8 ]], [[ -2, -4, -6, -8 ], [ -1, -3, -5, -7 ]] ];
Console.WriteLine("Jagged 3D Array Terse Syntax Lambda Expression");
Console.WriteLine($"Jagged 3D Array Terse Syntax Length: {jagged3DTerse.Length}" );
Console.WriteLine($"Jagged 3D Array Terse Syntax Count(): {jagged3DTerse.Count()}" );
jagged3DTerse.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write($"{y}, "))
);
Console.WriteLine();
}
);
// Cannot initialize type 'int[*,*]' with a collection expression because the type is not constructible.
int[ , ] array2DInitialization = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// int[ , ] array2D = [ array2DInitialization ];
int[] array1 = [ 1, 3, 5, 7 ];
int[] array2 = [ 2, 4, 6, 8 ];
int[] array3 = [ -2, -4, -6, -8 ];
int[] array4 = [ -1, -3, -5, -7 ];
int[][][] terseJagged3DFromArrays = [ [array1], [array2], [array3, array4] ];
Console.WriteLine("Terse Syntax Jagged 3D Array From Arrays Lambda Expression");
Console.WriteLine($"Terse Syntax Jagged 3D Array From Arrays Length: {terseJagged3DFromArrays.Length}" );
Console.WriteLine($"Terse Syntax Jagged 3D Array From Arrays Count(): {terseJagged3DFromArrays.Count()}" );
terseJagged3DFromArrays.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
// The spread element, ..e in a collection expression adds all the elements in that expression.
// The argument must be a collection type.
int[] terseArrayFromSpreadElements = [ .. array1, .. array2, .. array3, .. array4 ];
Console.WriteLine("Terse Syntax Array From Spread Elements");;
Console.WriteLine($"Terse Syntax Array From Spread Elements Length: {terseArrayFromSpreadElements.Length}" );
Console.WriteLine($"Terse Syntax Array From Spread Elements Count(): {terseArrayFromSpreadElements.Count()}" );
Console.WriteLine( string.Join(", ", terseArrayFromSpreadElements) );
int[][][] terseJagged3DFromSpreadElements1 = [ [[ .. array1, .. array2, .. array3, ..array4]] ];
Console.WriteLine("Terse Syntax Jagged 3D Array From Spread Elements 1 Lambda Expression");;
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 1 Length: {terseJagged3DFromSpreadElements1.Length}" );
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 1 Count(): {terseJagged3DFromSpreadElements1.Count()}" );
terseJagged3DFromSpreadElements1.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
int[][][] terseJagged3DFromSpreadElements2 = [ [[ .. array1, .. array2]], [[.. array3, ..array4]] ];
Console.WriteLine("Terse Syntax Jagged 3D Array From Spread Elements 2 Lambda Expression");;
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 2 Length: {terseJagged3DFromSpreadElements2.Length}" );
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 2 Count(): {terseJagged3DFromSpreadElements2.Count()}" );
terseJagged3DFromSpreadElements2.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
int[][][] terseJagged3DFromSpreadElements3 = [ [[ .. array1, .. array2]], [[.. array3]], [[..array4]] ];
Console.WriteLine("Terse Syntax Jagged 3D Array From Spread Elements 3 Lambda Expression");;
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 3 Length: {terseJagged3DFromSpreadElements3.Length}" );
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 3 Count(): {terseJagged3DFromSpreadElements3.Count()}" );
terseJagged3DFromSpreadElements3.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
int[][][] terseJagged3DFromSpreadElements4 = [ [[ .. array1]], [[.. array2]], [[.. array3, ..array4]] ];
Console.WriteLine("Terse Syntax Jagged 3D Array From Spread Elements 4 Lambda Expression");;
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 4 Length: {terseJagged3DFromSpreadElements4.Length}" );
Console.WriteLine($"Terse Syntax Jagged 3D Array From Spread Elements 4 Count(): {terseJagged3DFromSpreadElements4.Count()}" );
terseJagged3DFromSpreadElements4.ToList().ForEach
(
x =>
{
x.ToList().ForEach
(
y => y.ToList().ForEach(y => Console.Write( $"{y}, "))
);
Console.WriteLine();
}
);
Console.WriteLine();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("3. ref readonly parameters");
/*************************************************************************************************************************/
// CS 7.x added in parameters as a way to pass readonly references.
// in parameters allow both variables and values, and can be used without any annotation on arguments.
// The addition of ref readonly parameters enables more clarity for APIs that might be using ref parameters or in parameters:
// APIs created before in was introduced might use ref even though the argument isn't modified.
// Those APIs can be updated with ref readonly.
// It won't be a breaking change for callers, as would be if the ref parameter was changed to in.
// An example is System.Runtime.InteropServices.Marshal.QueryInterface.
// APIs that take an in parameter, but logically require a variable.
// A value expression doesn't work.
// An example is System.ReadOnlySpan<T>.ReadOnlySpan<T>(T).
// APIs that use ref because they require a variable, but don't mutate that variable.
// An example is System.Runtime.CompilerServices.Unsafe.IsNullRef.
/*
,---------------------.---------------------.------------------------.---------------------.---------------------.
| Callsite annotation | ref parameter | ref readonly parameter | in parameter | out parameter |
|---------------------|---------------------|------------------------|---------------------|---------------------|
| ref | Allowed | Allowed | Warning | Error |
|---------------------|---------------------|------------------------|---------------------|---------------------|
| in | Error | Allowed | Allowed | Error |
|---------------------|---------------------|------------------------|---------------------|---------------------|
| out | Error | Error | Error | Allowed |
|---------------------|---------------------|------------------------|---------------------|---------------------|
| No annotation | Error | Warning | Allowed | Error |
`---------------------'---------------------'------------------------'---------------------'---------------------'
// NB: CS 12: in parameter with ref callsite annotation produces a warning
*/
/*
,---------------------.---------------------.------------------------.---------------------.---------------------.
| Value kind | ref parameter | ref readonly parameter | in parameter | out parameter |
|---------------------|---------------------|------------------------|---------------------|---------------------|
| rvalue | Error | Warning | Allowed | Error |
|---------------------|---------------------|------------------------|---------------------|---------------------|
| lvalue | Allowed | Allowed | Allowed | Allowed |
`---------------------'---------------------'------------------------'---------------------'---------------------'
// NB: lvalue means a variable (i.e., a value with a location; does not have to be writable/assignable) and rvalue means any kind of value.
*/
string? name = "CS 12";
int? number = 12;
Console.WriteLine("Inline arrays lvalue string");
InlineArrayNames lvalueInlineArrayNames = new();
// InlineArray(26)
Enumerable.Range(0, 26).ToList().ForEach(x => lvalueInlineArrayNames[x] = ((char)((x + 65))).ToString() );
foreach (string element in lvalueInlineArrayNames)
{
Console.Write($"{element}, ");
}
Console.WriteLine();
Console.WriteLine("Inline arrays lvalue int");
InlineArrayNumbers lvalueInlineArrayNumbers = new();
// InlineArray(10)
Enumerable.Range(0, 10).ToList().ForEach(x => lvalueInlineArrayNumbers[x] = x * x);
foreach (int element in lvalueInlineArrayNumbers)
{
Console.Write($"{element}, ");
}
Console.WriteLine();
RefParameter<string?>(ref name);
RefParameter<int?>(ref number);
// RefParameter<string?>(in name); // Error
// RefParameter<int?>(in number); // Error
// RefParameter<string?>(out name); // Error
// RefParameter<int?>(out number); // Error
// No annotation
// RefParameter<string?>(name); // Error
// RefParameter<int?>(number); // Error
// rvalue
// RefParameter<string?>("CS 12"); // Error
// RefParameter<int?>(12); // Error
// lvalue
RefParameter<InlineArrayNames>(ref lvalueInlineArrayNames);
RefParameter<InlineArrayNumbers>(ref lvalueInlineArrayNumbers);
RefReadonlyParameter<string?>(ref name);
RefReadonlyParameter<int?>(ref number);
RefReadonlyParameter<string?>(in name);
RefReadonlyParameter<int?>(in number);
// RefReadonlyParameter<string?>(out name); // Error
// RefReadonlyParameter<int?>(out number); // Error
// No annotation
// RefReadonlyParameter<string?>(name); // Warning CS9192
// RefReadonlyParameter<int?>(number);// Warning CS9192
// rvalue
// RefReadonlyParameter<string?>("CS 12"); // Warning CS9193
// RefReadonlyParameter<int?>(12); // Warning CS9193
// lvalue
RefReadonlyParameter<InlineArrayNames>(ref lvalueInlineArrayNames);
RefReadonlyParameter<InlineArrayNumbers>(ref lvalueInlineArrayNumbers);
// CS 12
// InParameter<string?>(ref name); // Warning CS9191
// InParameter<int?>(ref number); // Warning CS9191
InParameter<string?>(in name);
InParameter<int?>(in number);
// InParameter<string?>(out name); // Error
// InParameter<int?>(out number); // Error
// No annotation
InParameter<string?>(name);
InParameter<int?>(number);
// rvalue
InParameter<string?>("CS 12");
InParameter<int?>(12);
// lvalue
InParameter<InlineArrayNames>(in lvalueInlineArrayNames);
InParameter<InlineArrayNumbers>(in lvalueInlineArrayNumbers);
// OutParameter<string?>(ref name); // Error
// OutParameter<int?>(ref number); // Error
// OutParameter<string?>(in name); // Error
// OutParameter<int?>(in number); // Error
OutParameter<string?>(out name);
OutParameter<int?>(out number);
// No annotation
// OutParameter<string?>(name); // Error
// OutParameter<int?>(number); // Error
// rvalue
// OutParameter<string?>("CS 12"); // Error
// OutParameter<int?>(12); // Error
// lvalue
OutParameter<InlineArrayNames>(out lvalueInlineArrayNames);
OutParameter<InlineArrayNumbers>(out lvalueInlineArrayNumbers);
void RefParameter<T>(ref T refT)
{
Console.WriteLine($"ref parameter {refT}");
}
void RefReadonlyParameter<T>(ref readonly T refT)
{
Console.WriteLine($"ref parameter {refT}");
}
void InParameter<T>(in T inT)
{
Console.WriteLine($"in parameter {inT}");
}
void OutParameter<T>(out T? outT)
{
outT = default(T);
Console.WriteLine($"in parameter {outT}");
}
Console.WriteLine();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("4. Default lambda parameters");
/*************************************************************************************************************************/
// Beginning with C# 12, you can provide default values for parameters on lambda expressions.
// The syntax and the restrictions on default parameter values are the same as for methods and local functions.
// .NET >= 6
/*
// Math.ReciprocalEstimate(Double) Method
// Returns an estimate of the reciprocal of a specified number.
// On ARM64 hardware this may use the FRECPE instruction which performs a single Newton-Raphson iteration.
// On hardware without specialized support, this may just return 1.0 / d.
*/
var arm64FRECPE = (double source, bool sqrtDefault = true) => sqrtDefault ? Math.ReciprocalSqrtEstimate(source) : Math.ReciprocalEstimate(source);
// default
Console.WriteLine(arm64FRECPE(25)); //.2
// explicit
Console.WriteLine(arm64FRECPE(25, false)); // .04
Console.WriteLine();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("5. Alias any type");
/*************************************************************************************************************************/
List<Jet> jetRecords = [ new Jet("F-22", "Raptor", "Steel Marble"), new Jet("F-35", "Panther", "Golf Ball"), ]; // 2. Collection expressions
Console.WriteLine("Alias Stealth");
Stealth stealthEnumerable = jetRecords.AsEnumerable();
Console.WriteLine(string.Join(", ", stealthEnumerable));
List<Aircraft> aircraftRecords = [ new Aircraft("Boeing", "Dreamliner", 787), new Aircraft("Airbus", "Superjumbo", 380), ]; // 2. Collection expressions
Console.WriteLine("Alias Air");
Air airEnumerable = aircraftRecords.AsEnumerable();
Console.WriteLine(string.Join(", ", airEnumerable));
List<Vehicle> vehicleAbstractRecords = [new Jet("Rafale", "Omnirole", "Composite"), new Aircraft("Falcon", "Super-Midsize", 6)]; // 2. Collection expressions
Console.WriteLine("Alias Horse");
Horse horseEnumerable = vehicleAbstractRecords.AsEnumerable();
Console.WriteLine(string.Join(", ", horseEnumerable));
Console.WriteLine($"List<Task<Jet>> async await Lambda Expression");
List<Task<Jet>> listTaskJet = jetRecords.Select
(
async x =>
{
await Task.Delay(500);
{
return x;
}
}
).ToList();
Console.WriteLine($"List<Task<Jet>> Count: {listTaskJet.Count}");
Console.WriteLine($"List<Task<Jet>> await");
foreach (Task<Jet> taskJet in listTaskJet)
{
// The 'await' operator can only be used within an async method.
// Parameters or locals of type Span and ReadOnlySpan cannot be declared in async methods or async lambda expressions.
Console.Write($"await Task Jet: {await taskJet}, ");
}
Console.WriteLine();
Console.WriteLine($"Task<List<Jet>> Task.Run()");
Task<List<Jet>> taskListJet = Task.Run( () => jetRecords );
// The 'await' operator can only be used within an async method.
// Parameters or locals of type Span and ReadOnlySpan cannot be declared in async methods or async lambda expressions.
// await taskListJet;
Console.WriteLine($"Task<List<Jet>> Count: {taskListJet.Result.Count}");
Console.WriteLine($"Task<List<Jet>> Result");
Console.WriteLine(string.Join(", ", taskListJet.Result));
Console.WriteLine("static Alias");
string[] sorter = ["Alpha", "Beta", "Gamma", "Delta", "Epsilon" ];
Console.WriteLine(string.Join(", ", sorter));
// global using static System.Array;
Sort(sorter);
Console.WriteLine(string.Join(", ", sorter));
Console.WriteLine("Custom Alias");
// global using Axes = (double X, double Y);
Tuple tup = (Math.Pow(5, 5), Math.Pow(5, 10));
Console.WriteLine(tup);
// System.Collections.Generic.List is not nullable type
Console.WriteLine($"Is System.Collections.Generic.List nullable type: {Nullable.GetUnderlyingType(typeof(System.Collections.Generic.List<string?>)) is not null}");
// System.Array? is nullable type
Console.WriteLine("The typeof operator cannot be used on a nullable reference type: System.Array?");
// System.Array is not nullable type
Console.WriteLine($"Is System.Array nullable type: {Nullable.GetUnderlyingType(typeof(System.Array)) is not null}");
// string? is nullable type
// The typeof operator cannot be used on a nullable reference type
Console.WriteLine("The typeof operator cannot be used on a nullable reference type: string?");
// string is not nullable type
Console.WriteLine($"Is string nullable type: {Nullable.GetUnderlyingType(typeof(string)) is not null}");
// int? is nullable type
Console.WriteLine($"Is int? nullable type: {Nullable.GetUnderlyingType(typeof(int?)) is not null}");
// int is not nullable type
Console.WriteLine($"Is int nullable type: {Nullable.GetUnderlyingType(typeof(int)) is not null}");
Console.WriteLine();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("6. Inline arrays");
/*************************************************************************************************************************/
Console.WriteLine("6. Inline arrays string");
InlineArrayNames namesInlineArray = new();
// InlineArray(26)
Enumerable.Range(0, 26).ToList().ForEach(x => namesInlineArray[x] = ((char)((x + 65))).ToString() );
foreach (string element in namesInlineArray)
{
Console.Write($"{element}, ");
}
Console.WriteLine();
Console.WriteLine("6. Inline arrays int");
InlineArrayNumbers numbersInlineArray = new();
// InlineArray(10)
Enumerable.Range(0, 10).ToList().ForEach(x => numbersInlineArray[x] = x * x);
foreach (int element in numbersInlineArray)
{
Console.Write($"{element}, ");
}
Console.WriteLine("\n");
/*************************************************************************************************************************/
/*************************************************************************************************************************/
Console.WriteLine("7. Experimental attribute");
Console.WriteLine("8. Interceptors");
/*************************************************************************************************************************/
CS12ExperimentalAttributeInterceptors experimentalAttributeInterceptors = new();
experimentalAttributeInterceptors.Print();
/*************************************************************************************************************************/
/*************************************************************************************************************************/
// 1. Primary constructors
/*************************************************************************************************************************/
// You can now create primary constructors in any class and struct. Primary constructors are no longer restricted to record types.
// Adding a primary constructor to a class prevents the compiler from declaring an implicit parameterless constructor.
class PrimaryConstructors(string Alpha, string Beta)
// Primary constructor parameters are in scope for the entire body of the class.
{
// warning CS9113: Parameter 'Alpha' is unread.
// warning CS9113: Parameter 'Beta' is unread.
// If commented out
public override string ToString() => $"Alpha: {Alpha}, Beta: {Beta}";
// To ensure that all primary constructor parameters are definitely assigned, all explicitly declared constructors must call the primary constructor using this() syntax.
// In other words, a constructor declared in a type with parameter list must have 'this' constructor initializer.
// Explicit parameterless constructor
public PrimaryConstructors() : this("Explicit A", "Explicit B") { }
}
struct PrimaryConStruct(string Gamma, string Delta = "G")
// Primary constructor parameters are in scope for the entire body of the struct.
{
// warning CS9113: Parameter 'Gamma' is unread.
// warning CS9113: Parameter 'Delta' is unread.
// If commented out
public override string ToString() => $"Gamma: {Gamma}, Delta: {Delta}";
// warning CS0649: Field 'PrimaryConStruct.InstanceFieldInStruct' is never assigned to, and will always have its default value 0
// public int InstanceFieldInStruct;
public int InstanceFieldInStruct = 0;
// In a struct, the implicit parameterless constructor initializes all fields, including primary constructor parameters to the 0-bit pattern.
// CS 11 // Auto-default structs
// Comment out the explicit parameterless constructor to verify
// Explicit parameterless constructor
public PrimaryConStruct() : this("Explicit C", "Explicit D") { }
}
// The compiler generates public properties for primary constructor parameters only in record types, either record class or record struct types.
record class RecordClass(bool IsPropertyGenerated);
// Optionally, you can omit the class keyword to create a record class.
record RecordDefraultClass(bool IsPropertyGenerated);
record struct RecordStruct(bool IsPropertyGenerated);
// Nonrecord classes and structs might not always want this behavior for primary constructor parameters.
// class NonrecordClass(bool IsPropertyGenerated); // warning CS9113: Parameter 'IsPropertyGenerated' is unread.
// struct NonrecordStruct(bool IsPropertyGenerated); // warning CS9113: Parameter 'IsPropertyGenerated' is unread.
/*************************************************************************************************************************/
/*************************************************************************************************************************/
// 6. Inline arrays
/*************************************************************************************************************************/
// Inline arrays
// Inline arrays are used by the runtime team and other library authors to improve performance in your apps.
// Inline arrays enable a developer to create an array of fixed size in a struct type.
// A struct with an inline buffer should provide performance characteristics similar to an unsafe fixed size buffer.
// You likely won't declare your own inline arrays, but you use them transparently when they're exposed as System.Span<T> or System.ReadOnlySpan<T> objects from runtime APIs.
[System.Runtime.CompilerServices.InlineArray(26)]
struct InlineArrayNames
{
// Inline array element field cannot be declared as required, readonly, volatile, or as a fixed size buffer.
private string _scalar;
}
[System.Runtime.CompilerServices.InlineArray(10)]
struct InlineArrayNumbers
{
// Inline array element field cannot be declared as required, readonly, volatile, or as a fixed size buffer.
private int _scalar;
}
// Inline array struct must declare one and only one instance field.
// Instance fields of readonly structs must be readonly
// Inline array element field cannot be declared as required, readonly, volatile, or as a fixed size buffer.
// Hence
// readonly struct cannot be used as a type argument
// ref struct may not be used as a type argument
// [System.Runtime.CompilerServices.InlineArray(20)]
// 'Inline arrays' language feature is not supported for an inline array type that is not valid as a type argument, or has element type that is not valid as a type argument.
/*
ref struct InlineArrayRefNumbers
{
// 'Inline arrays' language feature is not supported for an inline array type that is not valid as a type argument, or has element type that is not valid as a type argument
// private ref int _scalar;
private int _scalar;
}
*/
/*************************************************************************************************************************/
/*************************************************************************************************************************/
// Environment Properties
/*************************************************************************************************************************/
class EnvironmentProperties
{
public void Print()
{
System.Console.WriteLine($"System.Environment.OSVersion: {System.Environment.OSVersion}");
System.Console.WriteLine($"System.Environment.OSVersion.Platform: {System.Environment.OSVersion.Platform}");
System.Console.WriteLine($"System.Environment.OSVersion.Version: {System.Environment.OSVersion.Version}");
System.Console.WriteLine($"System.Environment.OSVersion.VersionString: {System.Environment.OSVersion.VersionString}");
System.Console.WriteLine($"System.Environment.OSVersion.Version.Major: {System.Environment.OSVersion.Version.Major}");
System.Console.WriteLine($"System.Environment.OSVersion.Version.Minor: {System.Environment.OSVersion.Version.Minor}");
System.Console.WriteLine($"System.Environment.OSVersion.Platform == System.PlatformID.Win32NT: {System.Environment.OSVersion.Platform == System.PlatformID.Win32NT}");
System.Console.WriteLine($"System.Environment.OSVersion.Platform == System.PlatformID.Unix: {System.Environment.OSVersion.Platform == System.PlatformID.Unix}");
// Mono JIT compiler version 6.12.0.206 'PlatformID' does not contain a definition for 'Other'
// System.Console.WriteLine($"System.Environment.OSVersion.Platform == System.PlatformID.Other: {System.Environment.OSVersion.Platform == System.PlatformID.Other}");
// System.PlatformID.Win32NT
// System.Console.WriteLine($"System.Environment.OSVersion.ServicePack: {System.Environment.OSVersion.ServicePack}");
// System.Environment.Version property returns the .NET runtime version for .NET 5+ and .NET Core 3.x
// Not recommend for .NET Framework 4.5+
System.Console.WriteLine($"System.Environment.Version: {System.Environment.Version}");
// <-- Keep this information secure! -->
// System.Console.WriteLine($"System.Environment.UserName: {System.Environment.UserName}");
// <-- Keep this information secure! -->
// System.Console.WriteLine($"System.Environment.MachineName: {System.Environment.MachineName}");
// <-- Keep this information secure! -->
// System.Console.WriteLine($"System.Environment.UserDomainName: {System.Environment.UserDomainName}");
System.Console.WriteLine($"System.Environment.Is64BitOperatingSystem: {System.Environment.Is64BitOperatingSystem}");
System.Console.WriteLine($"System.Environment.Is64BitProcess: {System.Environment.Is64BitProcess}");
// <-- Keep this information secure! -->
// System.Console.WriteLine("CurrentDirectory: {0}", System.Environment.CurrentDirectory);
// <-- Keep this information secure! -->
// System.Console.WriteLine("SystemDirectory: {0}", System.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+
System.Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}");
System.Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture: {System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture}");
System.Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.OSArchitecture: {System.Runtime.InteropServices.RuntimeInformation.OSArchitecture}");
System.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'
// System.Console.WriteLine($"System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier: {System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier}");
// <-- Keep this information secure! -->
#if comments
System.Console.WriteLine("Environment Variables:");
foreach (System.Collections.DictionaryEntry de in System.Environment.GetEnvironmentVariables())
{
System.Console.WriteLine("{0} = {1}", de.Key, de.Value);
}
#endif
}
}
/*************************************************************************************************************************/
// CS12FileScopedNamespaceGlobalAliasAnyTypeExtensions.cs
/*
// A global using directive cannot be used in a namespace declaration.
global using File.Scoped.Namespace.Global.Alias.Any.Type;
// Source file can only contain one file-scoped namespace declaration.
namespace File.Scoped.Namespace.Global.Alias.Any.Type.Extensions;
public record Jet(string RealName, string Nickname, string RadarCrossSection) : Vehicle(RealName, Nickname);
public sealed record Aircraft(string RealName, string Nickname, int AircraftClassificationNumber) : Vehicle(RealName, Nickname);
*/
// CS12FileScopedNamespaceGlobalAliasAnyType.cs
/*
// Source file can only contain one file-scoped namespace declaration.
namespace File.Scoped.Namespace.Global.Alias.Any.Type;
public record Vehicle(string RealName, string Nickname);
*/
// CS12ExperimentalAttributeInterceptors.cs
/*
using System.Globalization;
using System.Runtime.CompilerServices;
using ExperimentalAttribute;
class CS12ExperimentalAttributeInterceptors
{
public void Print()
{
ExperimentalAttributeInterceptors interceptorsExperimentalAttribute = new();
interceptorsExperimentalAttribute.InterceptableMethod(1);
interceptorsExperimentalAttribute.InterceptableMethod(2);
interceptorsExperimentalAttribute.InterceptableMethod(3); // Line: 12 // Column: 43
interceptorsExperimentalAttribute.InterceptableMethod(4);
interceptorsExperimentalAttribute.InterceptableMethod(5);
}
}
// <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);ExperimentalAttribute</InterceptorsPreviewNamespaces> // CS12.csproj
namespace ExperimentalAttribute
{
static class Interceptors
{
// An interceptor is a method that can declaratively substitute a call to an interceptable method with a call to itself at compile time.
// This substitution occurs by having the interceptor declare the source locations of the calls that it intercepts.
// Interceptors provide a limited facility to change the semantics of existing code by adding new code to a compilation, for example in a source generator.
// NB: Visual Studio defaults to absolute path of the file.
const string file = "CS12ExperimentalAttributeInterceptors.cs";
[InterceptsLocation(file: file, line: 12, position: 43)]
public static void InterceptableMethod(this ExperimentalAttributeInterceptors attribute, int number)
{
CultureInfo currentCulture = CultureInfo.CurrentCulture;
// US "en-US" // OR // UK "en-GB"
CultureInfo culture = new CultureInfo("en-US");
Thread.CurrentThread.CurrentCulture = culture;
Console.WriteLine($"CultureInfo: {Thread.CurrentThread.CurrentCulture.Name}");
// Console.WriteLine(DateTime.Now);
// Console.WriteLine(DateTime.Now.ToString(culture));
// string format = "dddd, MMMM dd, yyyy, h:mm:ss.fff tt, K";
string format = "dddd, MMMM dd, yyyy, h:mm:ss.fff tt, zzz";
// Console.WriteLine(DateTime.Now.ToString(format));
Console.WriteLine(DateTime.Now.ToString(format, culture));
// DateTime dateTimeParseExact = DateTime.ParseExact(DateTime.Now.ToString(format, culture), format, culture);
// Console.WriteLine(dateTimeParseExact);
}
}
class ExperimentalAttributeInterceptors
{
public void InterceptableMethod(int number)
{
Console.WriteLine($"interceptable {number}");
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class InterceptsLocationAttribute(string file, int line, int position) : Attribute
{
void Print() => Console.WriteLine($"file: {file}, line: {line}, position: {position}");
}
}
*/
// CS12.csproj
/*
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);ExperimentalAttribute</InterceptorsPreviewNamespaces>
</PropertyGroup>
</Project>
*/
// NB
// default
// CS 8 Nullable reference type
// <Nullable>enable</Nullable> in .csproj
// CS 10 Implicit using directives
// <ImplicitUsings>enable</ImplicitUsings> in .csproj
// % dotnet run --configuration Debug
// % cat obj/Debug/net8.0/CS12.GlobalUsings.g.cs
// Or
// % dotnet run --configuration Release
// % cat obj/Release/net8.0/CS12.GlobalUsings.g.cs
/*
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
*/
// dotnet run
/*
Environment Properties
System.Environment.OSVersion: Unix 15.0.1
System.Environment.OSVersion.Platform: Unix
System.Environment.OSVersion.Version: 15.0.1
System.Environment.OSVersion.VersionString: Unix 15.0.1
System.Environment.OSVersion.Version.Major: 15
System.Environment.OSVersion.Version.Minor: 0
System.Environment.OSVersion.Platform == System.PlatformID.Win32NT: False
System.Environment.OSVersion.Platform == System.PlatformID.Unix: True
System.Environment.Version: 8.0.6
System.Environment.Is64BitOperatingSystem: True
System.Environment.Is64BitProcess: True
System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription: .NET 8.0.6
System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture: Arm64
System.Runtime.InteropServices.RuntimeInformation.OSArchitecture: Arm64
System.Runtime.InteropServices.RuntimeInformation.OSDescription): Darwin 24.0.0 Darwin Kernel Version 24.0.0: Tue Sep 24 23:39:07 PDT 2024; root:xnu-11215.1.12~1/RELEASE_ARM64_T6000
1. Primary constructors
Alpha: A, Beta: B
Alpha: Explicit A, Beta: Explicit B
Gamma: C, Delta: G
0
IsPropertyGenerated for record class: True
IsPropertyGenerated for record default class: True
IsPropertyGenerated for record struct: True
2. Collection expressions
Terse Syntax Array string[]
Alpha, Beta, Gamma, Delta
Terse Syntax Array int[]
111, 333, 666, 888
Terse Syntax List<string>
Zeta, Eta, Theta, Iota, Kappa
Terse Syntax List<int>
222, 444, 555, 777
Terse Syntax Span<char>
Terse Syntax ReadOnlySpan<string>
Terse Syntax ReadOnlySpan<string?>
Terse Syntax ReadOnlySpan<int?>
Terse Syntax Jagged 3D Array Lambda Expression
Terse Syntax Jagged 3D Array Length: 5
Terse Syntax Jagged 3D Array Count(): 5
1, 3, 5, 7, 11, 33, 55, 77, 99,
2, 4, 6, 8, 22, 44, 66, 88, 222, 444, 666, 888, 2222, 4444, 6666, 8888,
3, 5, 7, 9,
-4, -6, -44, -66, -444, -666,
0,
Terse Syntax Jagged 3D Array Lambda Expression Index
1, 3, 5, 7, 11, 33, 55, 77, 99
2, 4, 6, 8, 22, 44, 66, 88, 222, 444, 666, 888, 2222, 4444, 6666, 8888
3, 5, 7, 9
-4, -6, -44, -66, -444, -666
0
Terse Syntax Jagged 3D Array Lambda Expression string.Join
1, 3, 5, 7, 11, 33, 55, 77, 99,
2, 4, 6, 8, 22, 44, 66, 88, 222, 444, 666, 888, 2222, 4444, 6666, 8888,
3, 5, 7, 9,
-4, -6, -44, -66, -444, -666,
0,
Terse Syntax Jagged 3D Array Lambda Expression IEnumerable
Terse Syntax Jagged 3D Array IEnumerable Count(): 5
1, 3, 5, 7, 11, 33, 55, 77, 99,
2, 4, 6, 8, 22, 44, 66, 88, 222, 444, 666, 888, 2222, 4444, 6666, 8888,
3, 5, 7, 9,
-4, -6, -44, -66, -444, -666,
0,
Jagged 3D Array Terse Syntax Lambda Expression
Jagged 3D Array Terse Syntax Length: 3
Jagged 3D Array Terse Syntax Count(): 3
1, 3, 5, 7,
2, 4, 6, 8,
-2, -4, -6, -8, -1, -3, -5, -7,
Terse Syntax Jagged 3D Array From Arrays Lambda Expression
Terse Syntax Jagged 3D Array From Arrays Length: 3
Terse Syntax Jagged 3D Array From Arrays Count(): 3
1, 3, 5, 7,
2, 4, 6, 8,
-2, -4, -6, -8, -1, -3, -5, -7,
Terse Syntax Array From Spread Elements
Terse Syntax Array From Spread Elements Length: 16
Terse Syntax Array From Spread Elements Count(): 16
1, 3, 5, 7, 2, 4, 6, 8, -2, -4, -6, -8, -1, -3, -5, -7
Terse Syntax Jagged 3D Array From Spread Elements 1 Lambda Expression
Terse Syntax Jagged 3D Array From Spread Elements 1 Length: 1
Terse Syntax Jagged 3D Array From Spread Elements 1 Count(): 1
1, 3, 5, 7, 2, 4, 6, 8, -2, -4, -6, -8, -1, -3, -5, -7,
Terse Syntax Jagged 3D Array From Spread Elements 2 Lambda Expression
Terse Syntax Jagged 3D Array From Spread Elements 2 Length: 2
Terse Syntax Jagged 3D Array From Spread Elements 2 Count(): 2
1, 3, 5, 7, 2, 4, 6, 8,
-2, -4, -6, -8, -1, -3, -5, -7,
Terse Syntax Jagged 3D Array From Spread Elements 3 Lambda Expression
Terse Syntax Jagged 3D Array From Spread Elements 3 Length: 3
Terse Syntax Jagged 3D Array From Spread Elements 3 Count(): 3
1, 3, 5, 7, 2, 4, 6, 8,
-2, -4, -6, -8,
-1, -3, -5, -7,
Terse Syntax Jagged 3D Array From Spread Elements 4 Lambda Expression
Terse Syntax Jagged 3D Array From Spread Elements 4 Length: 3
Terse Syntax Jagged 3D Array From Spread Elements 4 Count(): 3
1, 3, 5, 7,
2, 4, 6, 8,
-2, -4, -6, -8, -1, -3, -5, -7,
3. ref readonly parameters
Inline arrays lvalue string
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,
Inline arrays lvalue int
0, 1, 4, 9, 16, 25, 36, 49, 64, 81,
ref parameter CS 12
ref parameter 12
ref parameter InlineArrayNames
ref parameter InlineArrayNumbers
ref parameter CS 12
ref parameter 12
ref parameter CS 12
ref parameter 12
ref parameter InlineArrayNames
ref parameter InlineArrayNumbers
in parameter CS 12
in parameter 12
in parameter CS 12
in parameter 12
in parameter CS 12
in parameter 12
in parameter InlineArrayNames
in parameter InlineArrayNumbers
in parameter
in parameter
in parameter InlineArrayNames
in parameter InlineArrayNumbers
4. Default lambda parameters
0.19970703125
0.0399169921875
5. Alias any type
Alias Stealth
Jet { RealName = F-22, Nickname = Raptor, RadarCrossSection = Steel Marble }, Jet { RealName = F-35, Nickname = Panther, RadarCrossSection = Golf Ball }
Alias Air
Aircraft { RealName = Boeing, Nickname = Dreamliner, AircraftClassificationNumber = 787 }, Aircraft { RealName = Airbus, Nickname = Superjumbo, AircraftClassificationNumber = 380 }
Alias Horse
Jet { RealName = Rafale, Nickname = Omnirole, RadarCrossSection = Composite }, Aircraft { RealName = Falcon, Nickname = Super-Midsize, AircraftClassificationNumber = 6 }
List<Task<Jet>> async await Lambda Expression
List<Task<Jet>> Count: 2
List<Task<Jet>> await
await Task Jet: Jet { RealName = F-22, Nickname = Raptor, RadarCrossSection = Steel Marble }, await Task Jet: Jet { RealName = F-35, Nickname = Panther, RadarCrossSection = Golf Ball },
Task<List<Jet>> Task.Run()
Task<List<Jet>> Count: 2
Task<List<Jet>> Result
Jet { RealName = F-22, Nickname = Raptor, RadarCrossSection = Steel Marble }, Jet { RealName = F-35, Nickname = Panther, RadarCrossSection = Golf Ball }
static Alias
Alpha, Beta, Gamma, Delta, Epsilon
Alpha, Beta, Delta, Epsilon, Gamma
Custom Alias
(3125, 9765625)
Is System.Collections.Generic.List nullable type: False
The typeof operator cannot be used on a nullable reference type: System.Array?
Is System.Array nullable type: False
The typeof operator cannot be used on a nullable reference type: string?
Is string nullable type: False
Is int? nullable type: True
Is int nullable type: False
6. Inline arrays
6. Inline arrays string
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,
6. Inline arrays int
0, 1, 4, 9, 16, 25, 36, 49, 64, 81,
7. Experimental attribute
8. Interceptors
interceptable 1
interceptable 2
CultureInfo: en-US
Thursday, October 31, 2024, 2:45:05.727 AM, +05:30
interceptable 4
interceptable 5
*/
// Credit
/*
https://dotnet.microsoft.com/
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment