我們在原理 (2) 中處理了許多內建的型別,不過還有幾種比較棘手的型別,其中一個就是列舉 (enumeration),列舉也是一種實值型別,只是它大多用來作為限制常數的用途 (使用有意義的指令取代數字),而且它不能用在泛型,所以 where 等於是不能用 (雖然有替代方案)。
我們在原理 (2) 中處理了許多內建的型別,不過還有幾種比較棘手的型別,其中一個就是列舉 (enumeration),列舉也是一種實值型別,只是它大多用來作為限制常數的用途 (使用有意義的指令取代數字),而且它不能用在泛型,所以 where 等於是不能用 (雖然有替代方案)。
因此,我們在原理 (2) 中所用的 ITypeConverter 就無法沿用,我們必須要額外給定一個方法,傳入列舉型別,才能夠順利將轉型成列舉,所以我們新寫了一個 EnumConverter,但不實作原有的 Convert(),而是加一個新的 Convert():
public class EnumConverter : ITypeConverter
{
public object Convert(object ValueToConvert)
{
throw new NotImplementedException();
}
public object Convert(Type EnumType, object ValueToConvert)
{
if (!EnumType.IsEnum)
throw new InvalidOperationException("ERROR_TYPE_IS_NOT_ENUMERATION");
return System.Convert.ChangeType(Enum.Parse(EnumType, ValueToConvert.ToString()), EnumType);
}
}
然後,新增一個 Product 類別,以及等等會用到的 ReorderLevel 列舉:
public enum ReorderLevel
{
None = 0,
Lowest = 5,
Lower = 10,
Medium = 15,
More = 20,
High = 25,
Often = 30
}
public class Product
{
public string ProductID { get; set; }
public string ProductName { get; set; }
public ReorderLevel ReorderLevel { get; set; }
}
接著修改主程式,這次要取的資料是 Products 表格的 ProductID, ProductName 以及 ReorderLevel 三個欄位:
class ProgramStep3
{
static void Main(string[] args)
{
// step 2. handling data type convert.
SqlConnection db = new SqlConnection("initial catalog=Northwind; integrated security=SSPI");
SqlCommand dbcmd = new SqlCommand(@"SELECT ProductID, ProductName, ReorderLevel FROM Products", db);
List<Product> products = new List<Product>();
db.Open();
SqlDataReader reader = dbcmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
Product product = new Product();
for (int i = 0; i < reader.FieldCount; i++)
{
// TODO: implement data binding to object with enumeration.
}
products.Add(product);
}
reader.Close();
db.Close();
foreach (Product product in products)
{
Console.WriteLine("id: {0}, name: {1}, level: {2}",
product.ProductID, product.ProductName,
Enum.GetName(typeof(ReorderLevel), product.ReorderLevel));
}
Console.WriteLine("");
Console.WriteLine("Press ENTER to exit.");
Console.ReadLine();
}
}
再修改一下 TypeConverterFactory:
public class TypeConverterFactory
{
public static ITypeConverter GetConvertType<T>()
{
if (typeof(T) == typeof(int))
return (new IntegerConverter());
if (typeof(T) == typeof(long))
return (new LongConverter());
if (typeof(T) == typeof(short))
return (new ShortConverter());
if (typeof(T) == typeof(float))
return (new FloatConverter());
if (typeof(T) == typeof(double))
return (new DoubleConverter());
if (typeof(T) == typeof(decimal))
return (new DecimalConverter());
if (typeof(T) == typeof(bool))
return (new BooleanConverter());
if (typeof(T) == typeof(char))
return (new CharConverter());
if (typeof(T) == typeof(string))
return (new StringConverter());
if (typeof(T).IsEnum)
return (new EnumConverter());
return null;
}
public static ITypeConverter GetConvertType(Type T)
{
if (T == typeof(int))
return (new IntegerConverter());
if (T == typeof(long))
return (new LongConverter());
if (T == typeof(short))
return (new ShortConverter());
if (T == typeof(float))
return (new FloatConverter());
if (T == typeof(double))
return (new DoubleConverter());
if (T == typeof(decimal))
return (new DecimalConverter());
if (T == typeof(bool))
return (new BooleanConverter());
if (T == typeof(char))
return (new CharConverter());
if (T == typeof(string))
return (new StringConverter());
if (T.IsEnum)
return (new EnumConverter());
return null;
}
}
現在,我們就可以在 TODO 中加入資料繫結的功能了:
PropertyInfo property = product.GetType().GetProperty(reader.GetName(i));
Type propType = property.PropertyType;
TypeConverters.ITypeConverter typeConverter = TypeConverters.TypeConverterFactory.GetConvertType(propType);
if (!propType.IsEnum)
{
property.SetValue(product,
Convert.ChangeType(typeConverter.Convert(reader.GetValue(i)), propType), null);
}
else
{
TypeConverters.EnumConverter converter = typeConverter as TypeConverters.EnumConverter;
property.SetValue(product,
Convert.ChangeType(converter.Convert(propType, reader.GetValue(i)), propType), null);
}
由於 ITypeConverter 沒有 Convert(Type, object) 這個函式,只有 EnumConverter 才有,所以我們要先判斷屬性的型別是否是列舉,如果是,就用 EnumConverter 處理,否則仍用一般的作法處理。
試跑程式,會得到 ReorderLevel 的列舉值的名稱。