• 有時候在寫一些泛型程式的時候,難免會有一些轉型上的需求。 而在設計上,總不能當有需要轉型的時候就寫一個 if 來判斷此情況需要轉型成什麼類別,這樣就有點失去泛型的意義。 所以今天就分享一些小技巧,怎麼處理這些轉型的情況。

  • 使用父類別的小技巧,讓不同泛型型別的類別,一起放在同一個 List 裡面

TypeConverter

首先我設計一個 Convert 方法,主要功能是

  • TSource : 指定傳入的型別
  • TDestination : 輸出指定型別
MyConverter
  • cs
1
2
3
4
5
6
7
public class MyConverter
{
public static TDestination Convert<TSource, TDestination>(TSource value)
{
// return TDestination's Value
}
}

要完成這個轉型的功能,我們可以使用 TypeDescriptor 取得 TypeConverter , 使用 TypeConverter 幫我們完成轉型的功能,只要是原生型別預設能夠互相轉型,此功能就能夠幫我們做到轉型的這件事情,例如 : int, double, decimal 之間的轉型。

TypeConverter
  • cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyConverter
{
public static TDestination Convert<TSource, TDestination>(TSource value)
{
var converter = TypeDescriptor.GetConverter(typeof(TSource));

TDestination result = default(TDestination);

// 判斷能不能轉型
if (converter.CanConvertTo(typeof(TDestination)))
{
result = (TDestination)(converter.ConvertTo(value, typeof(TDestination)));
}

return result;
}
}

使用方式

Usage
  • cs
1
2
3
4
5
6
7
8
9
10
class Program
{
static void Main(string[] args)
{

var result = MyConverter.Convert<decimal, int>(102.2m);

Console.WriteLine(result); // print : 102
}
}

使用 Converter 讓轉型更靈活

在上面的例子中,會發生一些預設無法轉型的情況發生,例如: int 轉型成 DateTime。 當我們有這種情形發生的時候,盡量不要將怎麼轉型這件事情,寫在 Convert 方法裡面,我們可以在呼叫這個方法的時候,告訴這個方法怎麼轉型,例如: 我要 int 轉型成 DateTime 的方式先寫好,然後傳入。

以底下這個例子,我將傳入 型別是 int 的值,當作 DateTime 要增加幾天,最後輸出增加天數後的 DateTime。

Convert 方法傳入第 2 個參數 Converter<TSource, TDestination> converter , 當有傳入 converter 的時候,我就用 converter 來轉型

MyConverter
  • cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MyConverter
{
public static TDestination Convert<TSource, TDestination>(TSource value, Converter<TSource, TDestination> converter = null)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(TSource));

TDestination result = default(TDestination);

if (converter != null)
{
// 使用 converter 轉型
result = converter(value);
}
else
{
// 沒有傳入 converter ,則使用預設的方式轉型
result = (TDestination)(typeConverter.ConvertTo(value, typeof(TDestination)));
}

return result;
}
}

撰寫 int 如何轉型成 DateTime 的 delegate

我將 DateTime 時間設定在 2017/1/1 , 然後當我傳入 5 的時候,使用 Converter 將 5 轉型成 2017/1/1 加 5 天的 DateTime 時間。

Usage
  • cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Program
{
static void Main(string[] args)
{
Converter<int, DateTime> dateTimeConverter = x =>
{
var date = new DateTime(2017, 1, 1);
return date.AddDays(x);
};

var result = MyConverter.Convert<int, DateTime>(5, dateTimeConverter);

Console.WriteLine(result); // print : 2017/1/6
}
}

同場加映,使用父類別的小技巧

我要將 List 傳入一個能夠使用不同型別泛型的功能,例如下圖:

errorerror

當然!! 編譯器不會讓我們這樣做,那如果真的有功能想要達成這種方式的話,我們可以新增一個父類別,List 泛型就是父類別的型別就可以了,例如下圖:

successsuccess

參考

[Generic method]
[Using Base Types]
[TypeDescriptor]
[Converter]
[深度解析 TypeConverter & TypeConverterAttribute (一)]