---
# System prepended metadata

title: C# Genrics (2/18~2/20)
tags: [Generics, ASP.NET, constraints, note]

---

# C# Genrics (2/18~2/20)

###### tags: `Generics` `constraints` `note` `ASP.NET`

## Generics 的使用精神 - 在實作(instance)前，先不宣告型態
> Generics let you tailor a method, class, structure, or interface to the precise data type it acts upon. [2]

### Generic Methods 範例1
```csharp
public static bool CheckType<T1, T2>(T1 foo, T2 bar)
{
    return foo.GetType() == bar.GetType();
}

public class TestType1 {}
public class TestType2 {}
```
```csharp
Console.WriteLine(@"Compare ""123"" to 123");
Console.WriteLine(CheckType("123", 123));

TestType1 obj1 = new TestType1();
TestType2 obj2 = new TestType2();
Console.WriteLine(@"Compare obj1 to obj2");
Console.WriteLine(CheckType(obj1, obj2));

TestType1 obj3 = new TestType1();
Console.WriteLine(@"Compare obj1 to obj3");
Console.WriteLine(CheckType(obj1, obj3));
/* Output:
Compare "123" to 123
False
Compare obj1 to obj2
False
Compare obj1 to obj3
True
*/
```

## Generic Classes 
> Generic classes encapsulate operations that are not specific to a particular data type. The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on. \[4]

常用來實作各種資料結構或演算法
### Generic Class 範例1 - Dictionary \[5]
Ref[5]雖說他實作的是HashTable，但實際上因為它使用了Generics，他的Table於建立時就固定了Key與Value的DataType，所以他實作的應該為Dictionary而非HashTable。
而HashTable的寫法如下，取消Class HashTable的泛型，並將內容物的DataType改成dynamic即可。
```csharp
public struct KeyValue<K, V>
{
    public K Key { get; set; }
    public V Value { get; set; }
}

public class FixedSizeGenericHashTable
{
    private readonly int size;
    private readonly LinkedList<KeyValue<dynamic,dynamic>>[] items;

    public FixedSizeGenericHashTable(int size)
    {
        this.size = size;
        items = new LinkedList<KeyValue<dynamic,dynamic>>[size];
    }

    protected int GetArrayPosition(dynamic key)
    {
        int position = key.GetHashCode() % size;
        return Math.Abs(position);
    }

    public dynamic Find(dynamic key)
    {
        int position = GetArrayPosition(key);
        LinkedList<KeyValue<dynamic, dynamic>> linkedList = GetLinkedList(position);
        foreach (KeyValue<dynamic,dynamic> item in linkedList)
        {
            if (item.Key.Equals(key))
            {
                return item.Value;
            }
        }

        return default(dynamic);
    }

    public void Add(dynamic key, dynamic value)
    {
        int position = GetArrayPosition(key);
        LinkedList<KeyValue<dynamic, dynamic>> linkedList = GetLinkedList(position);
        KeyValue<dynamic, dynamic> item = new KeyValue<dynamic, dynamic>() { Key = key, Value = value };
        linkedList.AddLast(item);
    }

    public void Remove(dynamic key)
    {
        int position = GetArrayPosition(key);
        LinkedList<KeyValue<dynamic, dynamic>> linkedList = GetLinkedList(position);
        bool itemFound = false;
        KeyValue<dynamic, dynamic> foundItem = default(KeyValue<dynamic, dynamic>);
        foreach (KeyValue<dynamic,dynamic> item in linkedList)
        {
            if (item.Key.Equals(key))
            {
                itemFound = true;
                foundItem = item;
            }
        }

        if (itemFound)
        {
            linkedList.Remove(foundItem);
        }
    }

    protected LinkedList<KeyValue<dynamic, dynamic>> GetLinkedList(int position)
    {
        LinkedList<KeyValue<dynamic, dynamic>> linkedList = items[position];
        if (linkedList == null)
        {
            linkedList = new LinkedList<KeyValue<dynamic, dynamic>>();
            items[position] = linkedList;
        }

        return linkedList;
    }
}
```

## Features of Generics \[7]
- It helps you in code reuse, performance and **type safety**. \
例如Dictionary雖沒有固定Key Value的DataType，但在Dictionary一實作(new)後，Key Value的DateType就被固定了
- You can create your own generic classes, methods, interfaces and delegates. \
可以把delegate想成methods版的interface
- You can create generic **collection classes**. \
例如\[5]中的 LinkedList<KeyValue<K,V>>


## where T : constraint \[8] 
在使用Generics時，雖說未指定的DataType\<T>非常方便，但在Methods或Classes中要使用\<T>的物件下的一些Properties或Methods時，又會變得無法保證該DataType下一定有這些內容。 \
此時利用where T : constraint可以進一步限制or保護該Generics Classes/Methods。

### where T : class
MSDN描述如下
`where T : class`
> The type argument must be a reference type. This constraint applies also to any class, interface, delegate, or array type. In a nullable context in C# 8.0 or later, T must be a non-nullable reference type.

pass by ref 除了可以在讀入較大的物件時省時間空間，實在很難想到其他好處= =。 
如果要發揮直接修改該物件的優點，應該還要進一步限制T的DataType才對。

### where T : userdefine class 範例1
想像有一個車廠，專門組合 固定廠牌的車用零件 與 固定廠牌的車子控制系統，那我們就可以Generic class搭配constraint宣告一個CarFactory如下。 
之後利用已宣告好的Honda_Body與Tesla_Driverless來測試。
```csharp
public interface ICarComponent { }
public interface ICarControler { }

public class CarFactory<T1,T2> where T1 : ICarComponent where T2 : ICarControler
{
    public LinkedList<T1> CarComponents { get; set; }
    public LinkedList<T2> CarControlers { get; set; }
    public CarFactory()
    {
        this.CarComponents = new LinkedList<T1>();
        this.CarControlers = new LinkedList<T2>();
    }
}

public class Honda_Body : ICarComponent { }
public class Tesla_Driverless : ICarControler { }
```
```csharp
CarFactory<Honda_Body,Tesla_Driverless> plant1 = new CarFactory<Honda_Body, Tesla_Driverless>();
Honda_Body model1 = new Honda_Body();
Tesla_Driverless truckModel = new Tesla_Driverless();
Tesla_Driverless vanModel = new Tesla_Driverless();
plant1.CarComponents.AddLast(model1);
plant1.CarControlers.AddLast(truckModel);
plant1.CarControlers.AddLast(vanModel);
```
上面程式碼將 1個Honda的車體零件 與 2個特斯拉的無人駕駛模組 加入該車廠的組合選擇。
想像其內部有另外一個Assemble的Method可以根據 零件(ICarComponent)與 控制系統(ICarControler)來Return不同功能的車輛，此時where的限制就可以**確保**我們在Assemble時可以從特定class找到我們需要的資訊或功能。

MSDN還有很多不同constraint的例子，但沒有需求的話有點難體會他限制帶來的好處= =，感覺都可以直接用interface來限定DataType取代吧(?)

### 心得
1. HashTable對應到LinkedList可以在HashCode collision後繼續以Key利用foreach key in LinkedList查找。
2. Generic Class中的properties才能用generic type。
3. 於宣告時加了 readonly keyword 的 property 限制了一定要加readonly keyword才能修改property (Constructor中可不用加)。



## 參考資料
\[1] 陳明山,江通儒,ASP.NET Core 打造 軟體積木和應用系統 \
\[2] [C# generics](https://docs.microsoft.com/en-us/dotnet/standard/generics/) \
\[3] [Generic Methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-methods) \
\[4] [Generic Classes](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-classes) \
\[5] [example of a hashtable in C#](https://stackoverflow.com/questions/625947/what-is-an-example-of-a-hashtable-implementation-in-c) \
\[6] [Basics of Hash Tables](https://www.hackerearth.com/practice/data-structures/hash-tables/basics-of-hash-tables/tutorial/) \
\[7] [C# | Generics – Introduction](https://www.geeksforgeeks.org/c-sharp-generics-introduction/) \
\[8] [Constraints on type parameters](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters) 

