当扩展方法遇上反射

类型成员的可访问性(Accessibility)的作用,就是控制类型成员对外的可见性。

C#支持5种可访问性修饰符:public,private,internal,protected,protected internal,其中protected internal对应于CLR中的Family or Assembly,另外CLR还支持Family and Assembly的可访问性,只是C#不支持。

反射(Reflection)是一种在运行时提供类型发现和使用的机制,利用反射机制调用类型成员也称为晚期绑定(Late Binding)。

扩展方法是.Net3.0开始C#编译器提供的语法糖:他允许你定义一个静态方法,并用实例方法的语法调用它。编译器在内部对扩展方法应用ExtensionAttribute特性,这个特性是在System.Core程序集中定义的,所以定义扩展方法需要引用该程序集。

下面我将通过使用扩展方法和反射演示一种打破对象封装的方法,至少语法看上去如此:)

首先我构建一个封闭的类Class1

public sealed class Class1
{
private void CallPrivateMethod()
{
Console.WriteLine(
"Private method.");
}

public void CallPublicMethod()
{
Console.WriteLine(
"Public method.");
}
}

直接调用Class1.CallPrivateMethod当然会遇到编译错误 CS1061: “Class1”不包含“CallPrivateMethod”的定义,并且找不到可接受类型为“Class1”的第一个参数的扩展方法“CallPrivateMethod”(是否缺少 using 指令或程序集引用?)

class Program
{
static void Main(string[] args)
{
var obj
= new Class1();

// 可以访问
obj.CallPublicMethod();

// 编译错误
obj.CallPrivateMethod();
}
}

下面是扩展方法,定义扩展方法时务必检查实例是否为Null哦

public static class Class1Extensions
{
private static readonly MethodInfo privateMethod
= typeof(Class1).GetMethod("CallPrivateMethod"
BindingFlags.NonPublic | BindingFlags.Instance);

public static void CallPrivateMethod(this Class1 obj)
{
Console.WriteLine(
"Class1Extensions.CallPrivateMethod");
if (obj == null)
{
throw new NullReferenceException("Class1.CallPrivateMethod");
}
privateMethod.Invoke(obj,
new object[0]);
}
}

这下Main方法可以编译通过了,运行结果:

Public method.
Class1Extensions.CallPrivateMethod
Private method.

================================================================

或许你觉得反射可以很容易绑定并调用一个非公共成员,使得应用程序代码能访问私有成员(就像上文我说的那样)。

为防止晚期绑定不被滥用,CLR使用代码访问安全性(Code Access Security,CAS)来保证晚期绑定的安全。

进行晚期绑定时,CAS按下面顺序检查加载程序集权限:

1.检查成员编译时是否可见,如果可见则绑定成功

2.查询System.Security.Permissions.ReflectionPermission权限是否设置了ReflectionPermissionFlags.TypeInformation(绑定成员)或ReflectionPermissionFlags.MemberAccess(调用成员)标志,如果有设置则绑定成功

3.抛出System.Security.SecurityException异常

原文地址:https://www.cnblogs.com/neutra/p/1895125.html