Type 类提供了大量的属性和方法,但在一些基础性开发工作中,Type类功能还有些欠缺,尤其上在处理泛型类型时,如可空类型和泛型集合类型。下面的类就针对这些地方进行扩展。
扩展源码
2 {
3 public static bool IsNullableType( this Type type)
4 {
5 return (((type != null ) && type.IsGenericType) &&
6 (type.GetGenericTypeDefinition() == typeof (Nullable <> )));
7 }
8
9 public static Type GetNonNullableType( this Type type)
10 {
11 if (IsNullableType(type))
12 {
13 return type.GetGenericArguments()[ 0 ];
14 }
15 return type;
16 }
17
18 public static bool IsEnumerableType( this Type enumerableType)
19 {
20 return (FindGenericType( typeof (IEnumerable <> ), enumerableType) != null );
21 }
22
23 public static Type GetElementType( this Type enumerableType)
24 {
25 Type type = FindGenericType( typeof (IEnumerable <> ), enumerableType);
26 if (type != null )
27 {
28 return type.GetGenericArguments()[ 0 ];
29 }
30 return enumerableType;
31 }
32
33 public static bool IsKindOfGeneric( this Type type, Type definition)
34 {
35 return (FindGenericType(definition, type) != null );
36 }
37
38 public static Type FindGenericType( this Type definition, Type type)
39 {
40 while ((type != null ) && (type != typeof ( object )))
41 {
42 if (type.IsGenericType && (type.GetGenericTypeDefinition() == definition))
43 {
44 return type;
45 }
46 if (definition.IsInterface)
47 {
48 foreach (Type type2 in type.GetInterfaces())
49 {
50 Type type3 = FindGenericType(definition, type2);
51 if (type3 != null )
52 {
53 return type3;
54 }
55 }
56 }
57 type = type.BaseType;
58 }
59 return null ;
60 }
61 }
从名字上就以大体知道方法的功能,下面是部分测试代码,帮助大家理解:
测试代码
2 public void IsNullableTypeTest()
3 {
4 Assert.AreEqual( true , TypeExtension.IsNullableType( typeof ( int ? )));
5 Assert.AreEqual( false , TypeExtension.IsNullableType( typeof ( int )));
6 Assert.AreEqual( true , TypeExtension.IsNullableType( typeof (Nullable < DateTime > )));
7 Assert.AreEqual( false , TypeExtension.IsNullableType( typeof (DateTime)));
8 }
9 [TestMethod()]
10 public void GetNonNullableTypeTest()
11 {
12 Assert.AreEqual( typeof ( int ), TypeExtension.GetNonNullableType( typeof ( int ? )));
13 Assert.AreEqual( typeof (DateTime), TypeExtension.GetNonNullableType( typeof (Nullable < DateTime > )));
14 }
15 [TestMethod()]
16 public void IsEnumerableTypeTest()
17 {
18 Assert.AreEqual( true , TypeExtension.IsEnumerableType( typeof (IEnumerable < string > )));
19 Assert.AreEqual( true , TypeExtension.IsEnumerableType( typeof (Collection < int > )));
20 }
21 [TestMethod()]
22 public void GetElementTypeTest()
23 {
24 Assert.AreEqual( typeof ( int ), TypeExtension.GetElementType( typeof (IEnumerable < int > )));
25 Assert.AreEqual( typeof (DateTime), TypeExtension.GetElementType( typeof (Collection < DateTime > )));
26 }
27 [TestMethod()]
28 public void IsKindOfGenericTest()
29 {
30 Assert.AreEqual( true , TypeExtension.IsKindOfGeneric( typeof (List < string > ), typeof (IEnumerable <> )));
31 Assert.AreEqual( true , TypeExtension.IsKindOfGeneric( typeof ( string ), typeof (IComparable <> )));
32 }
33 [TestMethod()]
34 public void FindGenericTypeTest()
35 {
36 Assert.AreEqual( typeof (IEnumerable < string > ),
37 TypeExtension.FindGenericType( typeof (IEnumerable <> ), typeof (List < string > )));
38 }
代码就是最好的文档,想必大家已经都看明白了。
TypeHelper 是我从一个类库中提取的,它原本是一个 internal static class,内部的方法同样 internal static 。我仅仅是把 internal 改成了 public ,并在每个方法的第一个参数前加了个 this,最后给类中的方法按从简到难的顺序进行了排序。
也许是因为 TypeHelper 是一个内部类,并有强烈的应用语境,TypeHelper 并没有采用契约式编程的方式,甚至在命名上也做了一些省略: 如 IsEnumerableType、GetElementType 两个方法是实际是用来处理泛型集合类型的,但在方法名和参数名上并没有“Generic”的字眼。(如果传入非泛型类型或其它类型,将会产生难以预料的结果或异常。)
像这样简单将内部静态类 TypeHelper 中的静态方法公开为扩展方法是存在问题的,所以在应用之前,还得再做些工作。改进成为契约式编程的方式并不难,难的是给扩展方法起一个清晰明了简单易懂的名字,否则就不要扩展了。IsEnumerableType、GetElementType 应该体现出是对泛型集合进行操作,简单加上Generic字样后名字好长,也不好理解。(大家如果能想出好的名字,请发在回复中,不胜感激!)
补充
另外在使用时,我发现两处“奇怪”的地方,如下图:
调试至此处,type1为空,type2则是一个少见的奇怪类型。
TypeHelper 的出处我会在下一篇随笔中进行说明。
本人系列文章《c#扩展方法奇思妙用》,敬请关注!