...menustart
- C# vs .NET
- CLR (Common Language Runtime)
- Architecture of .NET Applications
- Fundamental
- compile & run C# code
...menuend
- C# is a programming language
- .NET is a framework for building applications on Windows
- .NET framework is not limited to c#. There are different languages that can target that framework and build applications using that framwork, e.g. F#, vb.net.
- .NET framework contains 2 components
- CLR(Common Language Runtime)
- Class Library
- When you compile your C# code, the result is what we called IL(intermediate language) code. It is independent of the computer on which it's running.
- Now we need something that would translate the IL code into the native code on the machine that running the application. And that is the job of CLR.
- So CLR is essentially an application that is sitting in the memory whose job is to translate the IL code into the machine code,
- and this process is called just-in-time compilation or JIT.
- Class
- building blocks
- Namespace
- a way to organize these classes
- a container of related classes
- Assembly (DLL or EXE)
- as the namespaces grow we need a different way of partitioning an application.
- an assembly is a container for related namespaces
- physically it's a file on the disk. It can either be an executable or a DLL.
Both ref and out parameter treated same at compile-time but different at run-time.
scenario | ref | out |
---|---|---|
before entering method | must initialize | |
before returning | must initialize inside the mothod | |
when to use | when the callee also want to change the value of passed parameter | when a method return multiple values |
- Usage of the "yield" keyword indicates that the method it appears in is an Iterator
- this means you can use it in a foreach loop
public static IEnumerable<int> YieldCounter(int limit = 10) { for (var i = 0; i < limit; i++) yield return i; }
- which you would call like this :
public static void PrintYieldCounterToConsole() { foreach (var counter in YieldCounter()) Console.WriteLine(counter); }
- this means you can use it in a foreach loop
- allows you to add new methods in the existing class or in the structure without modifying the source code of the original type
// static class public static class Extensions { // EXTENSION METHODS public static void Print(this object obj) { Console.WriteLine(obj.ToString()); } }
- this method extend to all
object
type - the first paramter
this object obj
is called Binding parameter
- this method extend to all
- how 2 use
int i = 3; i.Print(); // Defined below
- great for database interaction / return values
- any value type (i.e. not a class) can be made nullable by suffixing a
?
<type>? <var name> = <value>
int? nullable = null; // short hand for Nullable<int> Console.WriteLine("Nullable variable: " + nullable); bool hasValue = nullable.HasValue; // true if not null
- ?? is syntactic sugar for specifying default value (coalesce) in case variable is null
int notNullable = nullable ?? 0; // 0
- ?. is an operator for null-propagation - a shorthand way of checking for null
// Use the Print() extension method if nullable isn't null nullable?.Print();
- allow you to write code in line
Func<int, int> square = (x) => x * x; // Last T item is the return
- Let you handle unmanaged resources easily.
- Most of objects that access unmanaged resources (file handle, device contexts, etc.)
- implement the IDisposable interface. The using statement takes cleaning those IDisposable objects for you.
using (StreamWriter writer = new StreamWriter("log.txt")) { writer.WriteLine("Nothing suspicious here"); // At the end of scope, resources will be released. // Even if an exception is thrown. }
https://devblogs.microsoft.com/csharpfaq/parallel-programming-in-net-framework-4-getting-started/
var words = new List<string> {"dog", "cat", "horse", "pony"};
Parallel.ForEach(words,
new ParallelOptions() { MaxDegreeOfParallelism = 4 },
word =>
{
Console.WriteLine(word);
}
);
dynamic student = new ExpandoObject();
student.FirstName = "First Name"; // No need to define class first!
// You can even add methods (returns a string, and takes in a string)
student.Introduce = new Func<string, string>(
(introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo));
- almost all collections implement this, which gives you a lot of very useful Map / Filter / Reduce style methods
var bikes = new List<Bicycle>(); bikes.Sort(); // Sorts the array bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // Sorts based on wheels var result = bikes .Where(b => b.Wheels > 3) // Filters - chainable (returns IQueryable of previous type) .Where(b => b.IsBroken && b.HasTassles) .Select(b => b.ToString()); // Map - we only this selects, so result is a IQueryable<string> var sum = bikes.Sum(b => b.Wheels); // Reduce - sums all the wheels in the collection
- A delegate is a reference to a method.
- data & method
public static int count = 0; public static int Increment() { return ++count; }
- To reference the Increment method, first declare a delegate with the same signature
- i.e. takes no arguments and returns an int
// first declare a delegate with same signature public delegate int IncrementDelegate();
- data & method
- How to use
- instantiating the delegate, and passing the method in as an argument
IncrementDelegate inc = new IncrementDelegate(Increment);
- works like a function pointer
inc(); // => 1
- Delegates can be composed with the
+
operatorIncrementDelegate composedInc = inc; composedInc += inc; composedInc += inc; // composedInc will run Increment 3 times composedInc(); // => 4
- word as a function parameter
void someMethod( Mydelegate mydelegate ) { mydelegate( arg1, arg2 ); } ... someMethond( new Mydelegate( somefunc ) );
- instantiating the delegate, and passing the method in as an argument
- event allows only
+=
,-=
operators - An event can also be used to trigger delegates
// Create an event with the delegate type public static event IncrementDelegate MyEvent;
- How to use
- Subscribe to the event with the delegate
MyEvent += new IncrementDelegate(Increment); MyEvent += new IncrementDelegate(Increment);
- Trigger the event
- ie. run all delegates subscribed to this event
MyEvent();
- Subscribe to the event with the delegate
- To provide encapsulation and not exposing business logic.
- delegate need instantiate, it maybe null. but delegate can be invoked directly without checking.
- solve the problem by adding the event keyword.
- event can not be invoked directly, it will raise an error.
- delegate need instantiate, it maybe null. but delegate can be invoked directly without checking.
- To prevent Team Client from clearing all assign methods to delegates
- (You cannot do that for events):
MyEvent = null;
- (You cannot do that for events):
- constructor
// This is a specified constructor (it contains arguments) public Bicycle(int startCadence, int startSpeed, int startGear, string name, bool hasCardsInSpokes, BikeBrand brand) : base(startCadence, startSpeed) // calls base first { Gear = startGear; Cadence = startCadence; _speed = startSpeed; Name = name; _hasCardsInSpokes = hasCardsInSpokes; Brand = brand; } // Constructors can be chained public Bicycle(int startCadence, int startSpeed, BikeBrand brand) : this(startCadence, startSpeed, 0, "big wheels", true, brand) { }
- override
public override string Info() { string result = "PennyFarthing bicycle "; result += base.ToString(); // Calling the base version of the method return result; }
struct | class | |
---|---|---|
type | value type | reference type |
alloc | in stack, or inline in containing types, auto-deallocated | in heap, GC |
assignment | copy value | copy reference |
- when to use structure ?
- CONSIDER defining a struct instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.
- ❌ AVOID defining a struct unless the type has all of the following characteristics:
- It logically represents a single value, similar to primitive types (int, double, etc.).
- It has an instance size under 16 bytes.
- It is immutable.
- It will not have to be boxed frequently.
{
...
int someNumber = 420;
object someNumberObject = someNumber; // boxing , 20x slower
int unboxed = (int)someNumberObject ; // unboxing , 4x slower
...
}
-
why is it called boxing ?
- since object is a reference type allocated on the heap, you have to put that
someNumber
variable in a box and allocate on the heap.
- since object is a reference type allocated on the heap, you have to put that
-
another example
var arrayOfInts = Enumerable.Range(69,420).ToArray(); var arrayList = new ArrayList(arrayOfInts) ; // boxing, since underlying data structure is object[] var list = new List<int>(arrayOfInts); // will not boxing, generic solve that problem
# example cs
using System;
class cMain {
static void Main(String[] args) {
if ( args.Length < 1 ) {
Console.WriteLine( "usage: resp_verify <server response string>" );
return ;
}
string data = args[0];
Console.WriteLine( DOT_RESP_verify.resp_verify( data ) ) ;
}
}
#!/bin/sh
set -e
# compile
# -r:xxx.dll to reference an external dll
csc /out:resp_verify.exe *.cs
# run
mono resp_verify.exe '{"data":{"time":1626939359},"errcode":-1,"sig":"97f5e396ea0cadd9"}'