Skip to main content

C#

.NET Platform

.NET Core

  • Cross-Platform
  • Open Source
  • High Performance

.NET Framework

  • Windows Only
  • Not fully Open Source
  • Deprecated ?

Using in VS Code

  • Install .NET Core SDK
  • Install C# extension
  • Run dotnet new console in project folder
    • Run dotnet new --list list all template
    • Press F1.NET: Generate Assets for Build and Debug
      • Press F5 to run

Main Class

Reference

The Main method is the entry point of a C# application.

public class MainClass
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}

If more than one class that has a Main method, use MainEntryPoint or StartupObject

<PropertyGroup>
<StartupObject>Namespace.Program</StartupObject>
</PropertyGroup>

Starting in C# 9, can be Top-Level

// Main.cs
Console.WriteLine("Hello World");

Tools

Mono Cecil

  • Load existing managed assemblies, browse and inspect all the types, modify on the fly and save back the modified assembly.

ILSpy

  • .NET Decompiler

dnSpy

  • .NET Debugger
  • .NET Decompiler
  • .NET Assembly editor

BepInEx

  • For Unity
  • Included HarmonyX

Auto using

Auto using / import / include

Visual Studio 2019

  • Tools
  • Options
  • Text Editor
  • C#
  • IntelliSense
  • Enable Show items from unimported namespaces

VS Code

  • Enable C# Extension
  • Setting
    • Extension
    • C# configuration
    • Enable Enable Import Completion

Enable override, method auto completion

VS Code

  • Enable C# Extension
  • Setting
    • Extension
    • C# configuration
    • Enable Async Completion

@ Variable

Use KeyWord as identifier

var @is = true;

var

Ref

Implicitly type

var i = 0;
// same as
int i = 0;

var f = 1.0f;
// same as
float f = 1.0f;

typeof / GetType() / is

Reference

public class Animal { }

public class Cat : Animal { }

public static class TypeOfExample
{
public static void Main()
{
object cat = new Cat();
Console.WriteLine(cat is Animal); // True
Console.WriteLine(cat.GetType() == typeof(Animal)); // False

Console.WriteLine(cat is Cat); // True
Console.WriteLine(cat.GetType() == typeof(Cat)); // True
}
}

as / Cast

Reference

// Cast, convert E to type T
(T) E

E as T
// same as
E is T ? (T)(E) : (T)null
  • E is an expression that returns a value
  • T is the name of a type or a type parameter

String format

string.format("{0} is a {1}", "Cat", "animal");
// Cat is a animal

var a = "Cat";
var b = "animal";
$"{a} is a {b}";
// Cat is a animal

Use object as Dictionary key

Reference

public class DictKey
{
public int key;

public override int GetHashCode()
{
return this.key;
}

public override bool Equals(object obj)
{
return (obj is DictKey dictKey) &&
return this.key == dictKey.key;
}
}

Visual Studio has Quick Action to Generate Equals and GetHashCode

Reference

Generate Equals and GetHashCode

Implement GetHashCode()

// .NET Core
HashCode.Combine(value, ...);

For Collection

public class Hash
{
public List<int> list;

public override int GetHashCode()
{
var hashCode = new HashCode();
foreach (var item in list)
{
hashCode.Add(item);
}
return hashCode.ToHashCode();
}
}

?. / ?[] Null-conditional operator

Reference

a?.x

If a is null, the result is null, otherwise the result is a.x

a?.x()
a?.b?.c(d);
a?.b?[c];

If a is null, the result is null, and will not execute a.x(), otherwise the result is a.x()

The null-conditional operators are short-circuiting. That is, if one operation in a chain of conditional member or element access operations returns null, the rest of the chain doesn't execute.

a?[x]

If a is null, the result is null, otherwise the result is a[x]

byte[] <-> Hex string

byte[] to string

// .NET Framework
using System.Runtime.Remoting.Metadata.W3cXsd2001;

new SoapHexBinary(new byte[] { }).ToString();
BitConverter.ToString(new byte[] {});

Pure C# implement

public class Hex
{
private static readonly char[][] lookup = CreateLookupTable();

private static char[][] CreateLookupTable()
{
var table = new char[256][];
for (int i = 0; i < table.Length; i++)
{
string s = i.ToString("X2");
table[i] = new char[2] { s[0], s[1] };
}
return table;
}

public static string ToHex(byte[] bytes)
{
var result = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
var val = lookup[bytes[i]];
result[2 * i] = val[0];
result[2 * i + 1] = val[1];
}
return new string(result);
}
}

string to byte[]

// .NET Framework
SoapHexBinary.Parse("00aabbEEFF").Value;

Compute string hash

using System.Security.Cryptography;

public byte[] ComputeSHA1(string s)
{
using (SHA1 sha1 = SHA1.Create())
{
return sha1.ComputeHash(
Encoding.UTF8.GetBytes(s)
);
}
}

Overflow Check

Ref

checked(/* expression */);
unchecked(/* expression */);

int i = int.MaxValue;
// Overflow, throw System.OverflowException()
i = checked(i + 1);

int i = int.MaxValue;
// i = int.MinValue
i = unchecked(i + 1);

Event

Reference

using

Reference

using static type

using static System.Console;

class Program
{
static void Main()
{
WriteLine();
}
}

using alias

using SysCon = System.Console;
using ListOfString = System.Collections.Generic.List<string>;

Copy files after build

Reference

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyFiles" AfterTargets="AfterBuild">
<!-- Copy DLL/EXE to destination folder -->
<Copy SourceFiles="$(TargetDir)$(TargetFileName)" DestinationFolder="<folder>" />
<!-- <Copy SourceFiles="<file>[;<file>...]" DestinationFolder="<folder>" /> -->
</Target>
</Project>

Extension

namespace MathExtensionMethods
{
public static class MathExtensions
{
public static double Power(this Double number, Double power)
{
return Math.Pow(number, power);
}
}
}

(2.0).Power(16)

Single file app

Single File deployment

dotnet publish

Single execute file

.csproj
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>

</Project>
OptionCLI parameterDescription
PublishSingleFilePublish single file
SelfContained--self-contained [true|false]Contain .NET libraries and target runtime (> 60MB)
RuntimeIdentifier-r | --runtimeSpecifies the OS and CPU type (win-x86, win-x64, win-arm, win-arm64, ...)
PublishReadyToRunEnables ahead-of-time (AOT) compilation
  • Run dotnet publish
  • VS Code ▶ Run Taskpublish

Base Class

  • C# will auto call base constructor
  • Cannot have multiple base classes (Even abstract)
class BaseClass
{
public BaseClass() { }
public BaseClass(int i) { }
}

class ClassA : BaseClass
{
// Specify base class constructor
ClassA(int i) : base() {}
// or
ClassA(int i) : base(i) {}
}

Serialize

MessagePack

MessagePack

Attribute