C# Advanced Concepts

Overview

There are several advanced features of C# which are very powerful.

Assembly

An assembly is a collection of types and resources that are built to work together and form a logical unit of functionality. Assemblies are the building blocks of .NET applications. Assemblies has the code that the common language runtime executes.

Assemblies take the 2 forms

  • executable (.exe)
    • <compiler command> <module name>
      • csc test.cs
  • dynamic link library (.dll) files
    • <compiler command> -t:library <module name>
      • csc -t:library test.cs
    • is similar to a class library that contains types that will be referenced by other assemblies
    • has no entry point to begin execution

Note. Each assembly have only one entry point: DllMain, WinMain, or Main.

  • Static assemblies
    • stored on disk in portable executable (PE) files
    • include interfaces, classes, and resources like bitmaps, JPEG files, and other resource files
  • Dynamic assemblies
    • run directly from memory and aren’t saved to disk before execution
    • can save dynamic assemblies to disk after they have executed.

To use an assembly in an application, you must add a reference to it. To add a reference to a assembly. Use the following methods

  • static Load method of the System.Reflection.Assembly
  • GetType method of the Type class can load assemblies
  • Load method of the System.AppDomain class

Once an assembly is referenced, all the accessible types, properties, methods, and other members of its namespaces are available to your application as if their code were part of your source file.

Attributes

Attributes can add metadata (information about the types defined in a program) to the program. An attribute is actually an object that is associated with any of these elements: Assembly, Class, Method, Delegate, Enum, Event, Field, Interface, Property and Struct.

The attributes work by placing the name of the attribute enclosed in square brackets ([]) above the declaration of the entity to which it applies. It can contain parameters and the users can customize the attributes.

See here for more info.

In Unity, a public element with the attribute HideInInspector won’t appear in the inspector of Unity Editor. See here for Unity attribute.

A sample of serialization attribute is in the Serialization and Deserialization below.

Exceptions

See here for more info.

Generics

Generics makes it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.

A Generics class can also be inherited by other class. The derived class can specify the type of the class or it can inherit without specify the class. Generics class can also add Constrains to give some restrictions of the type.

[testGenerics] [CSharp]view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Collections.Generic;

namespace testCSharp
{
class MyGenericClass<type>
{
public type element1;
public MyGenericClass(type value = default(type))
{
element1 = value;
}

public type function1(type input)
{
Console.WriteLine(input);
return element1;
}
}

class MyDerivedClass1: MyGenericClass<string>
{
public MyDerivedClass1(string value)
{
element1 = value;
}
}

class MyDerivedClass2<type>: MyGenericClass<type> where type: class
{
public MyDerivedClass2(type value)
{
element1 = value;
}
}

class Program
{
static void Main(string[] args)
{
MyGenericClass<int> test1 = new MyGenericClass<int>(10);

int value1 = test1.function1(20); // 20
Console.WriteLine(value1); // 10

MyGenericClass<string> test2 = new MyGenericClass<string>("abc");

string value2 = test2.function1("jkl"); //"jkl"
Console.WriteLine(value2); //"abc"

MyDerivedClass1 test3 = new MyDerivedClass1("abc");
string value3 = test3.function1("jkl"); //"jkl"
Console.WriteLine(value3); //"abc"

MyDerivedClass2<int> test4 = new MyDerivedClass2<int>("abc"); //complie error, the 'type' must be a reference type
}
}
}

See here for more about generic.

Interface

Just define the return type and type of parameters, the specific implementation needs to be finish in derived class, which looks like the header file in C++, that only decare but not implement.

1
2
3
4
5
6
7
8
9
10
11
12
interface IMyInterface
{
void MethodToImplement();
}

class InterfaceImplementer : IMyInterface
{
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
}

See here for more info.

Lambda expression

Lambda expression can be used for anonymous method. The operator => is used.

1
2
3
4
5
6
7
8
9
Func<string> greet = () => "Hello, World!";
Console.WriteLine(greet());

event Handler OnTrigger;
OnTrigger += (sender, e) =>
{
Console.WriteLine(sender);
Console.WriteLine(e);
}

Properties

A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field (Member variables or methods in a class or structures). Properties can be used as if they are public data members, but they are actually special methods called accessors. This enables data to be accessed easily and still helps promote the safety and flexibility of methods.

[PropertiesSimple] [CSharp]view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Myclass
{
float seconds;

// Declare a Code property of type string:
public float Hours
{
get
{
return seconds / 3600.0f;
}
set
{
if (value < 0 || value > 24)
throw new ArgumentOutOfRangeException(
$"{nameof(value)} must be between 0 and 24.");

seconds = value * 3600;
}
}
}

In some cases, property get and set only return a value or assign a value, so the properties can be used auto-implemented to write. Note the code below only has the properties but no actual private field set. The required field of class of this kind of code will be set automatically during the compile.

1
2
3
4
5
6
public class SaleItem
{
public string Name { get; set; }

public int Price { get; set; }
}

The properties can also use body expression to simplify. Here we need to use the operator of =>. It could link a member with an expression. Here we don’t need to write the keywords of return but still require an private field.

[BodyExpressionProperties] [CSharp]view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SaleItem
{
string _name;
decimal _cost;

public string Name
{
get => _name;
set => _name = value;
}

public decimal Price
{
get => _cost;
set
{
if (value >= 0)
{
_cost = value;
}
}

}
}

The abstract class may have an abstract property, which can be implemented in the derived class

[AbstractProperties] [CSharp]view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class Person {
public abstract string Name {
get;
set;
}
}

class Student : Person {
private string name = "N.A";
private int age = 0;

// Declare a Name property of type string:
public override string Name {
get {
return name;
}
set {
name = value;
}
}
}

Serialization and Deserialization

It is the process of converting an object into a stream of bytes to store the object or transmit it to memory. The stream of bytes can be deserialized to the object.

To serialize an object, the object should be have a SerializableAttribute attribute. Fields within a class that don’t need to be serialized should include a NonSerializedAttribute attribute.

Users can use binary or XML serialization to serialize an object. Below is a sample to use basic serialization to serialize a class.

[testSerialization] [CSharp]view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace testCSharp
{

[Serializable]
class TestSerialize
{
public int ID = 13;
public string content = "test";

[NonSerialized]
public string content2 = "Costum";

public int function()
{
return 0;
}
}

class Program
{
static void Main(string[] args)
{
TestSerialize test1 = new TestSerialize();
test1.ID = 1234;
test1.content = "Hello World";
test1.content2 = "Hello World 2";
IFormatter formatter = new BinaryFormatter();
Stream fs = new FileStream("data.txt", FileMode.Create, FileAccess.Write);

formatter.Serialize(fs, test1);
fs.Close();

fs = new FileStream("data.txt", FileMode.Open, FileAccess.Read);
TestSerialize test2 = (TestSerialize)formatter.Deserialize(fs);

Console.WriteLine(test2.ID); // 1234
Console.WriteLine(test2.content); // Hello World
Console.WriteLine(test2.content2); // None
}
}
}

Thread

One thread if one execution flow for the code. For some parallel work in the same program, we can use multi-thread to save the total execution time.

See here for more information.

LINQ (Language Integrated Query)

Query expression is like the SQL language, it can search elements with some relationship. It starts with from and ends with select or group.

LINQ is the data object language that integrated into C#. It can be used for search, order, compare and summarize action.

[LINQSample] [CSharp]view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<User> users = new List<User>
{
new User{Name = "a", Age = 27},
new User{Name = "b", Age = 32},
new User{Name = "c", Age = 15}
}
Enumerable<Uesr> selectUsers = from user in users
where user.Age < 30
orderby user.Age descending
select user;

// Below is also work
var selectUsers = users.Where(user => user.Age < 30)
.OrderByDescending(user => user.Age).Select(user => user);

LINQ can be used in following scenarios.

  • Objects: object’s in code. e.g. class, collectiosn
  • XML: XML file
  • SQL: SQL database
  • Entities
  • Datasets