zoukankan      html  css  js  c++  java
  • 当扩展方法遇上反射

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

  • 相关阅读:
    Jenkins可用环境变量列表以及环境变量的使用(Shell/Command/Maven/Ant)
    CreateJS结合Falsh工具生成Canvas动画(加密字符串的由来)
    Linux下使用mv重命名文件或者移动文件(增强版的工具为rename)
    Windows7/8/10中无法识别USB设备的问题解决
    Eclipse工程中Java Build Path中的JDK版本和Java Compiler Compiler compliance level的区别(转)
    使用Docker部署Spring boot项目
    豆瓣API
    scrapy
    elasticsearch x-pack
    Document
  • 原文地址:https://www.cnblogs.com/neutra/p/1895125.html
Copyright © 2011-2022 走看看