类型成员的可访问性(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异常