dotnet CLI and Project file

dotnet

run

dotnet run --project ./projects/proj1/proj1.csproj
dotnet run --configuration Release
dotnet run -c Release --arch x64 --project ConsoleTest/ConsoleTest.csproj

#--no-build to run with no build

build

Builds a project and all of its dependencies.

Executable or library output

Whether the project is executable or not is determined by the <OutputType> property in the project file.

<PropertyGroup>
  <OutputType>Exe</OutputType>
</PropertyGroup>

To produce a library, omit the <OutputType> property or change its value to Library. The IL DLL for a library doesn’t contain entry points and can’t be executed.

  • --no-self-containedPublishes the application as a framework dependent application. A compatible .NET runtime must be installed on the target machine to run the application. Available since .NET 6 SDK.
dotnet build --source d1/d2 --output d3/d4 -c Release 

publish

dotnet publish – Publishes the application and its dependencies to a folder for deployment to a hosting system.

dotnet publish [<PROJECT>|<SOLUTION>] [-a|--arch <ARCHITECTURE>]
    [-c|--configuration <CONFIGURATION>]
    [-f|--framework <FRAMEWORK>] [--force] [--interactive]
    [--manifest <PATH_TO_MANIFEST_FILE>] [--no-build] [--no-dependencies]
    [--no-restore] [--nologo] [-o|--output <OUTPUT_DIRECTORY>]
    [--os <OS>] [-r|--runtime <RUNTIME_IDENTIFIER>]
    [--sc|--self-contained [true|false]] [--no-self-contained]
    [-s|--source <SOURCE>] [--use-current-runtime, --ucr [true|false]]
    [-v|--verbosity <LEVEL>] [--version-suffix <VERSION_SUFFIX>]

test

dotnet test

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
    <PackageReference Include="xunit" Version="2.4.2" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />
  </ItemGroup>

Project File

item group and property group examples

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        
    </PropertyGroup>
<ItemGroup>
      <PackageReference Include="Google.Cloud.Storage.V1" Version="4.4.0" />
        <None Update="settings.json">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="cloud_credintial.json">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="shell">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <Content Include="shell/*.*">
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>
    </ItemGroup>

C# Topics (Pattern matching)

Pattern matching

switch (aa)
{
    case {val:12}:
        Console.WriteLine("hello");
        break;
    case A aaa when aa.val2==13:
        Console.WriteLine(aaa.val);
        break;
}

Simplifying switch statements with switch expressions


Animal animal = new Animal() { Name = "tiger" };
string message = animal switch
{
    Animal fourLeggedCat when fourLeggedCat.Name=="cat"
        => $"small cat",
    Animal wildCat when wildCat.Name == "tiger"
        => $"big cat",
};
Console.WriteLine($"switch expression: {message}");

class Animal
{
    public string Name { get; set; }
}

with array patterns

int[] mm = new[]{1,2,3,4,5,6,7};
string vv=mm switch
{
    int[] vvv when mm is [_,2,_,4,..] => "one",
    int[] vvv when mm is {Length: 2} => "two"
};
Console.WriteLine(vv);


int[] mm = new[]{1,2,3,4,5,6,7};
string vv=mm switch
{
    [_,2,_,4,..] => "one",
    {Length: 2} => "two"
};
Console.WriteLine(vv);

relational patterns


bool b=v is (> 32) and (< 66);
string WaterState(int tempInFahrenheit) =>
    tempInFahrenheit switch
    {
        (> 32) and (< 212) => "liquid",
        < 32 => "solid",
        > 212 => "gas",
        32 => "solid/liquid transition",
        212 => "liquid / gas transition",
    };

var m=(12,44);
var l=new{val1=12,val2=44};
bool res=m is {Item1:12,Item2:_};
bool res2=l is {val1:12,val2:_};
Console.WriteLine($" m is {m}, and l is{l}");

C# Topics (1)

is operator

Console.WriteLine(new A{val1=1,val2=2} is { val1:1 ,val3:0});//true
public class A
{
    public int val1;
    public int val2;
    public int val3;
}

object o=default(object);
o is null //true
o is not null //false

is with patterns

object greeting = "Hello, World!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  // output: hello, world!
}

int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
    Console.WriteLine(a + b);  // output: 30
}

with expresion

with expression produces a copy of its operand with the specified properties and fields modified.
it work only with record and struct for class you can use IClonable or serialization and deserialization
you use object initializer syntax to specify what members to modify and their new values:

public record Point(int X, int Y);
public record NamedPoint(string Name, int X, int Y) : Point(X, Y);

public static void Main()
{
   Point p1 = new NamedPoint("A", 0, 0);
   Point p2 = p1 with { X = 5, Y = 3 };
   Console.WriteLine(p2 is NamedPoint);  // output: True
   Console.WriteLine(p2);  // output: NamedPoint { X = 5, Y = 3, Name = A }
}

stackalloc

allocate stacked memory for performance purposes

const int MaxStackLimit = 1024;
Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
Span<int> first = stackalloc int[3] { 1, 2, 3 };
Span<int> second = stackalloc int[] { 1, 2, 3 };
ReadOnlySpan<int> third = stackalloc[] { 1, 2, 3 };

Touples

public class A
{
    public int val1;
    public int val2;
    public int val3;
    
    (int v1,int v2,int v3) GetVal()
    {
        return (val1, val2);
    }
}


 (int t2,int t3) T = (1, 2);

anonymous object

var m = new { m = 12 };

List<int> vals = new(){ 1, 2, 3 };

A aa = new(1,2,3);

A aa = new(){val1=1,val2=2,val3=3};

Record

by default record is a class compares the record with == it compares the properties


record A
{
    public int a { get; init; }
    public int b { get; init; }
}

record AA(int a, int b);

extension method

public static class StringExtensions
{
    public static void GobbleGobble(this string s,int val) //new string("").GobbleGobble(12)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}

Reflections and Attributes

The .NET reflection services allow you to discover, using APIs from the System.Reflection namespace, the same information that you can see with the tools mentioned earlier. The key to this process is the type called System.Type, which contains members that expose all of a type’s metadata. This is done with the help of other types from the System.Reflection namespace

class A
{
    public int val;
    public int value
    {
        private set
        {
            val = value;
        }
        get
        {
            return val;
        }
    }
    public A(int i)
    {
        this.val = i;   
    }
}

A a=new A(12);
Type t1 =typeof(A);
Type t2 = a.GetType();
Type t3=Type.GetType("A");
Console.WriteLine((t1 == t2) && (t1 == t3));//true
A aa=(A)Activator.CreateInstance(t1, 12);
t1.GetProperty("value").GetSetMethod(true)?.Invoke(aa, new object[] { 44 });
Console.WriteLine(t1.GetField("val").GetValue(aa));//44

Attributes

Attributes provide meta-information about assemblies, types, and members. This meta-information is consumed by the compiler, the CLR, or tools that use reflection services to read them. Attributes are actually types that derive from the System.Attribute abstract class.

class DescriptionAttribute : Attribute
{
    public string Text { get; private set; }
    public bool Required { get; set; }
    public DescriptionAttribute(string description)
    {
        Text = description;
    }
}
[Description("Main component of the car", Required = true)]
class Engine
{
}
[AttributeUsage(AttributeTargets.Class|
                AttributeTargets.Struct|
                AttributeTargets.Method|
                AttributeTargets.Property|
                AttributeTargets.Field,
                AllowMultiple = true,
                Inherited = true)]
class DescriptionAttribute : Attribute
{
    public string Text { get; private set; }
    public bool Required { get; set; }
    public DescriptionAttribute(string description)
    {
        Text = description;
    }
}
[Serializable]
[Description("Main component of the car")]
[ComVisible(false)]
class Engine
{
}
[Serializable, 
 Description("Main component of the car"), 
 ComVisible(false)]
class Engine
{
}

Attributes In Reflections

var e = new Engine("M270 Turbo", 1600, 75.0);
var type = e.GetType();
var attributes = type.GetCustomAttributes(typeof(DescriptionAttribute), 
                                          true);
if (attributes != null)
{
    foreach (DescriptionAttribute attr in attributes)
    {
        Console.WriteLine(attr.Text);
    }
}
var properties = type.GetProperties();
foreach (var property in properties)
{
    var pattributes = 
      property.GetCustomAttributes(
         typeof(DescriptionAttribute), false);
    if (attributes != null)
    {
        foreach (DescriptionAttribute attr in pattributes)
        {
            Console.WriteLine(
              $"{property.Name} [{attr.Text}]");
        }
    }
}

Delgates , Events And Lambda expressions

Delegates

delegate is defined using the delegate keyword. The declaration looks like a function signature, but the compiler actually introduces a class that can hold references to methods whose signatures match the signature of the delegate. A delegate can hold references to either static or instance methods.

public enum Status { Started, Stopped }
public delegate void StatusChange(Status status);
public class Engine
{
    private StatusChange statusChangeHandler;// is Delegate return true
    public void RegisterStatusChangeHandler(StatusChange handler)
    {
        statusChangeHandler = handler;
    }
    public void Start()
    {
        // start the engine
        if (statusChangeHandler != null)
            statusChangeHandler(Status.Started);
    }
    public void Stop()
    {
        // stop the engine
        if (statusChangeHandler != null)
            statusChangeHandler(Status.Stopped);
    }
}

Combining delegates

ExpressionResult
null + d1d1
d1 + nulld1
d1 + d2[d1, d2]
d1 + [d2, d3][d1, d2, d3]
[d1, d2] + [d2, d3][d1, d2, d2, d3]
[d1, d2] – d1d2
[d1, d2] – d2d1
[d1, d2, d1] – d1[d1, d2]
[d1, d2, d3] – [d1, d2]d3
[d1, d2, d3] – [d2, d1][d1, d2, d3]
[d1, d2, d3, d1, d2] – [d1, d2][d1, d2, d3]
[d1, d2] – [d1, d2]null

Events

Events aren’t Delegate instances.

using System;

class Test
{
    public event EventHandler MyEvent
    {
        add
        {
            Console.WriteLine ("add operation");
        }
        
        remove
        {
            Console.WriteLine ("remove operation");
        }
    }  
    static void Main()
    {
        Test t = new Test();
        
        t.MyEvent += new EventHandler (t.DoNothing);
        t.MyEvent -= null;
    }
    void DoNothing (object sender, EventArgs e)
    {
    }
}
private EventHandler _myEvent;
    
public event EventHandler MyEvent
{
    add
    {
        lock (this)
        {
            _myEvent += value;
        }
    }
    remove
    {
        lock (this)
        {
            _myEvent -= value;
        }
    }        
}

Lambda expressions

  • The variables that are introduced in a lambda expression are not visible outside the lambda (for instance, in the enclosing method).
  • A lambda cannot capture inref, or out parameters from the enclosing method.
  • Variables that are captured by a lambda expression are not garbage collected, even if they would otherwise go out of scope until the delegate that the lambda is assigned to is garbage collected.
bool IsOdd(int n) { return n % 2 == 1; }
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list.RemoveAll(IsOdd);
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list.RemoveAll(delegate (int n) { return n % 2 == 1; });
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list.RemoveAll(n => n % 2 == 1);

Collections

IEnumerable and IEnumerator

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface.
This works for readonly access to a collection that implements that IEnumerable can be used with a foreach statement.
IEnumerator has two methods MoveNext and Reset. It also has a property called Current

class Demo : IEnumerable, IEnumerator {
   // IEnumerable method GetEnumerator()
   IEnumerator IEnumerable.GetEnumerator() {
      throw new NotImplementedException();
   }
   public object Current {
      get { throw new NotImplementedException(); }
   }
   // IEnumertor method
   public bool MoveNext() {
      throw new NotImplementedException();
   }
   // IEnumertor method
      public void Reset() {
      throw new NotImplementedException();
   }
}

List<T> collection

List<T> uses an array to store the elements. When the number of elements exceeds the size of the array, a new and larger array is allocated, and the content of the previous array is copied to the new one. 

var numbers = new List<int> {1, 2, 3}; // 1 2 3
numbers.Add(5);                        // 1 2 3 5
numbers.AddRange(new int[] { 7, 11 }); // 1 2 3 5 7 11
numbers.Insert(5, 1);                  // 1 2 3 5 7 1 11
numbers.Insert(5, 1);                  // 1 2 3 5 7 1 1 11
numbers.InsertRange(                   // 1 13 17 19 2 3 5..
    1, new int[] {13, 17, 19});        // ..7 1 1 11

numbers.Remove(1);              // 13 17 19  2  3  5  7  1  
                                // 1 11
numbers.RemoveRange(2, 3);      // 13 17  5  7  1  1 11
numbers.RemoveAll(e => e < 10); // 13 17 11
numbers.RemoveAt(1);            // 13 11
numbers.Clear();                // empty

var numbers = new List<int> { 1, 2, 3, 5, 7, 11 };
var a = numbers.Find(e => e < 10);      // 1
var b = numbers.FindLast(e => e < 10);  // 7
var c = numbers.FindAll(e => e < 10);   // 1 2 3 5 7

var numbers = new List<int> { 1, 1, 2, 3, 5, 8, 11 };
var a = numbers.FindIndex(e => e < 10);     // 0
var b = numbers.FindLastIndex(e => e < 10); // 5
var c = numbers.IndexOf(5);                 // 4
var d = numbers.LastIndexOf(1);             // 1
var e = numbers.BinarySearch(8);            // 5

var numbers = new List<int> { 1, 5, 3, 11, 8, 1, 2 };
numbers.Sort();     // 1 1 2 3 5 8 11
numbers.Reverse();  // 11 8 5 3 2 1 1

Sort() sorts the list according to a default or specified criteria. There are several overloads that allow us to specify either a comparison delegate or an IComparer<T> object, or even a sub-range of the list to sort. This operation is performed in O(n log n) in most cases but O (n2) in the worst-case scenario.

The Dictionary<TKey, TValue> collection

var languages = new Dictionary<int, string>()
{
    {1, "C#"}, 
    {2, "Java"}, 
    {3, "Python"}, 
    {4, "C++"}
};
languages.Add(5, "JavaScript");
languages.TryAdd(5, "JavaScript");
languages[6] = "F#";
languages[5] = "TypeScript";
Console.WriteLine($"Has 5: {languages.ContainsKey(5)}");
Console.WriteLine($"Has C#: {languages.ContainsValue("C#")}");

We can also iterate through the elements of a dictionary using an enumerator, in which case the key-value pairs are retrieved as KeyValuePair<TKey, TValue> objects:

foreach(var kvp in languages)
{
    Console.WriteLine($"[{kvp.Key}] = {kvp.Value}");
}

LINQ

class A : IComparable
{
    public int value{get;private set;}
    public A(int v)=>this.value = v;
    public int CompareTo(object obj) => this.value - (obj as A).value;
}


List<A> values2 = new List<A> { new A(v:34), new A(v: 45), new A(v: 76), new A(v: 23), new A(v: 54), new A(v: 33), new A(v: 65),new A(v:33), new A(v:23) };
var res = from x in values2 where x.value>50 orderby x ascending select x;
foreach(A v in res){ Console.WriteLine(v.value);}

var res = from x in values2 group x by x.value into gg where gg.Key>30  orderby gg.Key ascending select gg.Key ;
foreach(var v in res){ Console.WriteLine(v);}//33,34,45.....