反射扩展


  反射扩展的类名为 ReflectionExtension,大部份是对 Type 类型的扩展。

1、创建新实例

  New 方法用于构造一个指定类型的实例。类似于 Activator.CreateInstance 方法,但当类型实现 IAopSupport 接口类型时,它会调用 AOP 工厂来创建实例;如果构造类型为接口或抽象类时,它会动态编译类型并创建此类型的实例。

public interface IFood
{
    string Name { get; set; }
}

[TestMethod]
public void TestNew()
{
    var food = typeof(IFood).New<IFood>();
    food.Name = "food";
    Assert.AreEaqual("IFood_Impl", food.GetType()); // _Impl 表示是 AOP 生成的代理类型
}

  New 方法接收构造函数所需的参数,如果有多个构造函数,是 New 方法会根据参数类型去匹配一个构造函数,并使用此构造函数创建对象。

public class Food
{
    public Food(string name) { }
    public Food(string name, List<Material> materials) { }
}

public class Material
{
}

public class Flour : Material
{
}

[TestMethod]
public void TestNew()
{
    var food = typeof(Food).New<Food>("cake", new List<Material> { new Flour() });
}

  New 的另一个重载方法接收一个 IServiceProvider 实例,它能够从 IOC 里反转出最匹配的一个构造函数,并使用此构造函数创建对象。


2、解析 Type

  ParseType 允许从一个字符串中解析出类型,类似于 Type.GetType 方法。

[TestMethod]
public void TestParseType()
{
    var type = "System.Data.DataTable, System.Data".ParseType();
    Assert.IsNotNull(type);
}

3、判断是否是可空类型

  IsNullableType 方法判断指定的类别是否为可空类型。

[TestMethod]
public void TestIsNullableType()
{
    Assert.IsTrue(typeof(int?).IsNullableType());
    Assert.IsFalse(typeof(int?).IsNullableType());
}

4、获取非空类型的值类型

  GetNonNullableType 方法用于从可空类型中获取值类型。

[TestMethod]
public void TestGetNonNullableType()
{
    Assert.AreEqual(typeof(int), typeof(int?).GetNonNullableType());
}

5、构造可空类型

  GetNullableType 方法用于构造一个可空类型。

[TestMethod]
public void TestGetNullableType()
{
    Assert.AreEqual(typeof(int?), typeof(int).GetNullableType());
}

6、判断是否可为数字类型

  IsNumericType 方法用于判断指定的类型是否为数字型类型。比如 Int32Decimal 类型都可作为数字类型。

[TestMethod]
public void TestIsNumericType()
{
    Assert.IsTrue(typeof(int).IsNumericType());
    Assert.IsTrue(typeof(decimal?).IsNumericType());
    Assert.IsFalse(typeof(string).IsNumericType());
}

7、判断是否为匿名类型

  IsAnonymousType 方法用于判断指定的类型是否为匿名类。

[TestMethod]
public void TestIsAnonymousType()
{
    var obj = new { Name = "xy" };
    Assert.IsTrue(obj.GetType().IsAnonymousType());
    Assert.IsFalse(typeof(int).IsAnonymousType());
}

8、获取可枚举类型元素类型

  GetEnumerableElementType 方法用于从可枚举类型中提取元素类型。

[TestMethod]
public void TestGetEnumerableElementType()
{
    Assert.AreEqual(typeof(string), typeof(List<string>).GetEnumerableElementType());
    Assert.IsNull(typeof(string).GetEnumerableElementType());
    Assert.AreEqual(typeof(string), typeof(string[]).GetEnumerableElementType());
}

9、判断是否实现接口

  IsImplementInterface 方法用于判断是否实现了指定的接口。

private class BaseList<T> : List<T>, ICustomListNoMember
{
}

private class CustomList<T> : BaseList<T>
{
}

private interface ICustomListNoMember
{
}

[TestMethod]
public void TestIsImplementInterface()
{
    Assert.IsTrue(typeof(BaseList<string>).IsImplementInterface(typeof(ICustomListNoMember)));
    Assert.IsTrue(typeof(CustomList<string>).IsImplementInterface(typeof(ICustomListNoMember)));
    Assert.IsTrue(typeof(BaseList<string>).IsImplementInterface(typeof(IEnumerable<string>)));
}

10、判断是否直接实现接口

  IsDirectImplementInterface方法用于判断是否直接实现指定的接口。

[TestMethod]
public void TestIsDirectImplementInterface()
{
    Assert.IsTrue(typeof(List<string>).IsDirectImplementInterface(typeof(IList<string>)));
    Assert.IsFalse(typeof(BaseList<string>).IsDirectImplementInterface(typeof(IList<string>)));
}

  注意,无法使用此方法判断空接口类型,即该接口类型没有定义任何成员。


11、获取实现类型

  GetImplementType方法用于从父层级中搜索实现了接口的类。

[TestMethod]
public void TestGetImplementType()
{
    Assert.IsNull(typeof(TList<string>).GetImplementType(typeof(ICustomListNoMember)));
    Assert.AreEqual(typeof(BaseList<string>), typeof(SecondList<string>).GetImplementType(typeof(ICustomListNoMember)));
}

12、获取类型的层级

  GetHierarchyTypes 获取指定类型的继承层次,包括实现的接口。

[TestMethod]
public void TestGetHierarchyTypes()
{
    foreach (var type in typeof(BaseList<string>).GetHierarchyTypes())
    {
        Console.WriteLine(type);
    }
}

  输出结果如下:

BaseList`1[System.String]
System.Collections.Generic.List`1[System.String]
System.Object
System.Collections.Generic.IList`1[System.String]
System.Collections.Generic.ICollection`1[System.String]
System.Collections.Generic.IEnumerable`1[System.String]
System.Collections.IEnumerable
System.Collections.IList
System.Collections.ICollection
System.Collections.Generic.IReadOnlyList`1[System.String]
System.Collections.Generic.IReadOnlyCollection`1[System.String]
ICustomListNoMember

13、枚举父类型

  EachBaseTypes 方法用于枚举父类型。

[TestMethod]
public void TestEachBaseTypes()
{
    foreach (var type in typeof(BaseList<string>).EachBaseTypes())
    {
        Console.WriteLine(type);
    }
}

  输出结果如下:

System.Collections.Generic.List`1[System.String]
System.Object

14、获取成员声明类型

  GetMemberType 用于获取 MemberInfo 的声明类型。

private class ReflectionData
{
    public string TypeName;

    public event EventHandler Change;

    public string Name { get; set; }

    public int GetAge()
    {
        return 0;
    }
}

[TestMethod]
public void TestGetMemberType()
{
    var type = typeof(ReflectionData).GetType();
    Assert.AreEqual(typeof(string), type.GetMember("Name")[0].GetMemberType()); //属性
    Assert.AreEqual(typeof(string), type.GetMember("TypeName")[0].GetMemberType()); //字段
    Assert.AreEqual(typeof(System.EventHandler), type.GetMember("Change")[0].GetMemberType()); //事件
    Assert.AreEqual(typeof(int), type.GetMember("GetAge")[0].GetMemberType()); //方法
}

15、获取成员的值

  GetMemberValue 方法用于获取属性或字段的值。

[TestMethod]
public void TestGetMemberValue()
{
    var obj = new ReflectionData { Name = "fireasy", TypeName = "type" };
    var type = obj.GetType();
    Assert.AreEqual("fireasy", type.GetMember("Name")[0].GetMemberValue(obj));
    Assert.AreEqual("type", type.GetMember("TypeName")[0].GetMemberValue(obj));
}

16、判断自定义特性

  IsDefined 是一个泛型方法,它仅仅对 ICustomAttributeProvider 接口的 IsDefined 方法进行了封装。

[TestMethod]
public void TestIsDefined()
{
    Assert.IsTrue(MethodBase.GetCurrentMethod().IsDefined<TestMethodAttribute>());
}

17、获取自定义特性

  GetCustomAttributes 是一个泛型方法,它仅仅对 ICustomAttribute-rovider 接口的 GetCustomeAttributes 方法进行了封装。

[TestMethod]
public void TestGetCustomAttributes()
{
    Assert.AreEqual(1, MethodBase.GetCurrentMethod.GetCustomAttributes<TestMethodAttribute>().ToArray().Length);
}

18、基于缓存委托的反射操作

  FastGetValue 方法用于快速获取属性或字段的值;FastSetValue 方法用于快速设置属性或字段的值;FastInvoke 方法用于快速执行方法或构造函数。

  Fast 系列方法是由底层将属性或字段的存取动态编译成委托并存放在缓存中,要使用的时候能名提升性能。