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 };
(int Id, string Name) M=(1, "hello");

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

with == operator
class compare with reference
struct not accept
record compare with values


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);
    }
}
class Data1
{
    public int Id => 1; //property
    public string Name => "Test";//property
}

record Data2(int Id,string Name); //properties

var ( Id, Name) = new Data2(Id :1, "test");

Deconstruct function in class

class Data
{
    public int Id { set; get; }
    public string Name { set; get; }
    
    public void Deconstruct(out int Id, out string Name)
    {
        Id = this.Id;
        Name = this.Name;
    }
    
};

var ( Id, Name) = new Data(){Id =1, Name="test"};
( int Id, string Name) = new Data(){Id =1, Name="test"};

C++ Ranges

starting from c++ std 20 you can ranges STL library is coming up

first example


    #include "ranges"

    auto const ints =std::vector<int>{0,1,2,3,4,5};
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };

    auto res=ints | std::views::filter(even) | std::views::transform(square);
    for(const int& v : res){
        qDebug()<<v;
    }

the ranges it executed once start iterate it this in c++ std but in ranges-v3 you have to use ranges::views::indirect

auto vec=v::iota(-100,100)|v::take(10)|v::filter([](int val)->bool{return true;})|v::transform([](int val)->int{qDebug()<<val;return abs(val);});
    for (int i : vec) {
        qDebug()<< i ;
    }

-100 100
-99 99
-98 98
-97 97
-96 96
-95 95
-94 94
-93 93
-92 92
-91 91

zip ranges

    std::vector<int> vals{1,2,3,4,5,6};
    std::vector<int> vals2{11,22,33};
    auto res2=ranges::views::zip(vals,vals2);
    for(auto [val1,val2] : res2)
        std::cout<<val1<<":"<<val2<<std::endl;
//1:11   2:22   3:33

convert the output to vector

auto res=vals|ranges::views::take(5)|ranges::to<std::vector<int>>();

cycle the ranges

    std::vector<int> values{343,35,45,324,5,4};
    ranges::sort(values);//4 5 35 45 324 343
    auto res=values|ranges::views::take(100)|ranges::views::all|ranges::views::transform([](int v){ return v+45; })|ranges::to<std::vector<int>>();
    auto res2=res|ranges::views::cycle|ranges::views::take(10); //49 50 80 90 369 388 49 50 80 90 

Generate and accumilate

auto vi = views::for_each(views::ints(1, 6), [](int i) { return yield_from(views::repeat_n(i, i)); }) |to<std::vector>();
    // prints: [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
int sum = accumulate(views::ints(1, unreachable) | views::transform([](int i) {
                             return i * i;
                         }) | views::take(10),
                         0);
    // prints: 385

Actions

std::vector<int> vi{9, 4, 5, 2, 9, 1, 0, 2, 6, 7, 4, 5, 6, 5, 9, 2, 7,
                        1, 4, 5, 3, 8, 5, 0, 2, 9, 3, 7, 5, 7, 5, 5, 6, 1,
                        4, 3, 1, 8, 4, 0, 7, 8, 8, 2, 6, 5, 3, 4, 5};
    using namespace ranges;
    vi |= actions::sort | actions::unique;
    // prints: [0,1,2,3,4,5,6,7,8,9]

C++20(templates and concepts)

what is template value type?

value_type of the template is the type of template type
for example if you have std::vector<int> the value type is int like the example below …

template<typename T>
typename std::decay<typename T::value_type>::type fun2(T t){
    return *t.begin();
}

what is the “requires” keyword?

in before c++ 20 if you want to restrict type

template<class T>
class A{
public:
    using value_type=T;
};
template<class T>
class B:public A<T>{};
template<typename T,typename =std::enable_if_t<std::is_base_of_v<A<typename T::value_type>,T>>,
        typename =std::enable_if<is_arithmetic_v<typename T::value_type>>>
class tempClass{};
//tempClass<B<int>> correct
//tempClass<B<string>> is not correct string is not arithmetic type

but in c++20

template<typename T>
requires std::is_base_of_v<A<typename T::value_type>,T> && is_arithmetic_v<typename T::value_type>
class tempClass{};

what is the “concept” keyword?

template<class T>
concept MM=std::is_base_of_v<A<typename T::value_type>,T> && is_arithmetic_v<typename T::value_type>;


template<MM T>
class tempClass{};

//or

template<class T> requires MM<T>
class tempClass{};

C++ 20 (general subjects)

span array

void pspan(span<T> s) {
    cout << format("number of elements: {}\n", s.size());
    cout << format("size of span: {}\n", s.size_bytes());
    for(auto e : s) cout << format("{} ", e);
    cout << "\n";
}
int main() {
    int carray[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    pspan<int>(carray);
}

structure binding

int nums[] { 1, 2, 3, 4, 5 };
auto [ a, b, c, d, e ] = nums;
cout << format("{} {} {} {} {}\n", a, b, c, d, e);

array<int,5> nums { 1, 2, 3, 4, 5 };
auto [ a, b, c, d, e ] = nums;
cout << format("{} {} {} {} {}\n", a, b, c, d, e);

tuple<int, double, string> nums{ 1, 2.7, "three" };
auto [ a, b, c ] = nums;
cout << format("{} {} {}\n", a, b, c);

Initialize variables within if and switch statements

template<typename T>
const char * f(const T a) {
    return typeid(T).name();
}
int main() {
    cout << format("T is {}\n", f(47));
    cout << format("T is {}\n", f(47L));
    cout << format("T is {}\n", f(47.0));
    cout << format("T is {}\n", f("47"));
    cout << format("T is {}\n", f("47"s));
}

Use template argument deduction for simplicity and clarity

template<typename T>
const char * f(const T a) {
    return typeid(T).name();
}
int main() {
    cout << format("T is {}\n", f(47));
    cout << format("T is {}\n", f(47L));
    cout << format("T is {}\n", f(47.0));
    cout << format("T is {}\n", f("47"));
    cout << format("T is {}\n", f("47"s));
}
T is int
T is long
T is double
T is char const *

Use if constexpr to simplify compile-time decisions

template<typename T>
auto value_of(const T v) {
    if constexpr (std::is_pointer_v<T>) {
        return *v;  // dereference the pointer
    } else {
        return v;   // return the value
    }
}
int main() {
    int x{47};
    int* y{&x};
    cout << format("value is {}\n", value_of(x));  // value
    cout << format("value is {}\n", value_of(y));  
                                                // pointer
    return 0;
}