C#
.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
- Run
Main Class
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
- Load existing managed assemblies, browse and inspect all the types, modify on the fly and save back the modified assembly.
- .NET Decompiler
- .NET Debugger
- .NET Decompiler
- .NET Assembly editor
- 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
Implicitly type
var i = 0;
// same as
int i = 0;
var f = 1.0f;
// same as
float f = 1.0f;
typeof
/ GetType()
/ is
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
// 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 valueT
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
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
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
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
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
using
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
<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 execute file
<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>
Option | CLI parameter | Description |
---|---|---|
PublishSingleFile | Publish single file | |
SelfContained | --self-contained [true|false] | Contain .NET libraries and target runtime (> 60MB) |
RuntimeIdentifier | -r | --runtime | Specifies the OS and CPU type (win-x86 , win-x64 , win-arm , win-arm64 , ...) |
PublishReadyToRun | Enables ahead-of-time (AOT) compilation |
- Run
dotnet publish
- VS Code ▶ Run Task ▶ publish
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) {}
}