欢迎来到陆季疵的博客

人生莫作远行客,远行莫戍黄沙碛。黄沙碛下八月时, 霜风裂肤百草衰。尘沙晴天迷道路,河水悠悠向东去。 胡笳听彻双泪流,羁魂惨惨生边愁。原头猎火夜相向, 马蹄蹴蹋层冰上。不似京华侠少年,清歌妙舞落花前。

C#反射和特性的使用方法

Type类型

Type. IsAssignableFrom 方法:确定指定类型的实例是否能分配给当前类型实例。

            Console.WriteLine(typeof(Person).IsAssignableFrom(typeof(Student)));//True
            Console.WriteLine(typeof(Student).IsAssignableFrom(typeof(Person)));//False

Type. IsSubclassOf 方法:确定当前 Type 是否派生自指定的 Type。

            Console.WriteLine(typeof(Person).IsSubclassOf(typeof(Student)));//False
            Console.WriteLine(typeof(Student).IsSubclassOf(typeof(Person)));//True

 

Assembly程序集

1.1反射加载程序集

//获取最初执行代码的程序集路径
System.Reflection.Assembly.GetExecutingAssembly().CodeBase
//加载dll;当前程序集需存在这个名字的dll
Assembly assembly = Assembly.LoadFrom("TextDll.dll");

1.2获取类型

//获取程序集的指定类型,(类型名称需要包含命名空间)
Type type = assembly.GetType("TextDll.TestDemo");

//获取嵌套类型
Type type = assembly.GetType("TextDll.TestDemo+Student");

1.3创建类型的实例

//获取类型的实例
var obj = Activator.CreateInstance(type);//创建对象的实例,默认无参数构造函数

var obj2 = Activator.CreateInstance(type,new object[] { "123"});//创建对象的实例,一个字符串参数的构造方法

obj = Activator.CreateInstance(type,true);//创建对象的实例,使用私有构造方法

1.4获取实例的方法

//获取实例方法
var methodInfo = type.GetMethod("Quary");//通过名称获取类型的方法
methodInfo.Invoke(obj, null);//调用方法,静态方法可将实例为null

methodInfo = type.GetMethod("Quary",BindingFlags.Instance|BindingFlags.NonPublic);//实例私有方法
//获取普通类的泛型方法
var methodInfo = type.GetMethod("Quary");//通过名称获取类型的方法

var methodGeneric = methodInfo.MakeGenericMethod(new Type[] { typeof(int), typeof(string) });//确定方法的参数类型和个数(泛型方法)

methodGeneric.Invoke(obj, new object[] { 1, "Ant编程" });

1.5获取泛型类

            //获取泛型类的泛型方法
            Assembly assembly = Assembly.LoadFrom("TextDll.dll");//加载Dll,也可以完整路径

            Type type = assembly.GetType("TextDll.TestDemo`2");//获取泛型类,类型数量2

1.6创建泛型类的实例

            var typeNew = type.MakeGenericType(new Type[] { typeof(int), typeof(string) });//确定泛型类的参数类型

            var obj = Activator.CreateInstance(typeNew);//创建对象的实例,默认构造方法

1.7获取泛型类的泛型方法

            var methodInfo = type.GetMethod("Quary");//找到方法

            var methodGeneric = methodInfo.MakeGenericMethod(new Type[] { typeof(int), typeof(string) });//确定方法的参数类型和个数(泛型方法)
            methodGeneric.Invoke(obj, new object[] { 1, "Ant编程" });

1.8获取属性

            //获取属性
            Assembly assembly = Assembly.LoadFrom("TextDll.dll");//加载Dll,也可以完整路径

            Type type = assembly.GetType("TextDll.TestDemo");//获取泛型类,类型数量2

            var obj = Activator.CreateInstance(type);//创建对象的实例,默认构造方法

            var id = type.GetProperty("ID");
            if (id != null)
            {
                id.SetValue(obj, 2);
            }

            PropertyInfo[] propertyInfos = type.GetProperties();//所有属性

设置实例的属性,考虑属性是枚举类型

            var value = "First";
            var propertyInfo = typeof(Student).GetProperty("MyEnum");
            propertyInfo?.SetValue(student, propertyInfo.PropertyType.IsEnum ? Enum.Parse(propertyInfo.PropertyType, value)
                : Convert.ChangeType(value, propertyInfo.PropertyType), null);

 

1.9获取枚举类型的值

首先需要从内部了解一下枚举(Enumeration)

enumMyEnum

{

    AAA, BBB, CCC

}

//背后的IL是这样的:
.classprivate auto ansi sealed MyEnum

    extends [mscorlib]System.Enum

{

    .field publicstatic literal valuetype Mgen.MyEnum AAA = int32(0)

    .field publicstatic literal valuetype Mgen.MyEnum BBB = int32(1)

    .field publicstatic literal valuetype Mgen.MyEnum CCC = int32(2)

 

    .field public specialname rtspecialname int32 value__

}

其实枚举中的常量都是静态的字段。而枚举对象的值会保存在非静态的特殊字段value__中。因此,用反射来获取名称其实就是获取类型的所有静态字段就可以了,如下代码:

var fields =typeof(MyEnum).GetFields(BindingFlags.Static |BindingFlags.Public);

foreach (var fi in fields)

    Console.WriteLine(fi.Name);

对于值得获取也很简单,通过反射得到的代表静态字段的FieldInfo来获取值就可以,并且获取的值仍属于枚举类型的。如果想获取枚举背后的类型,仍需要Enum.GetUnderlyingType方法,如下代码:

var fields =typeof(MyEnum).GetFields(BindingFlags.Static |BindingFlags.Public);

foreach (var fi in fields)

{

    var value = fi.GetValue(null);

    Console.WriteLine("值:{0} 类型:{1} 枚举背后类型:{2}",

        value, value.GetType(), Enum.GetUnderlyingType(value.GetType()));

}

 2.0获取实例的委托属性并执行

            var assembly = Assembly.GetExecutingAssembly();

            var type = assembly.GetType("ConsoleTestUntil.Student");
            var obj = Activator.CreateInstance(type);

            var propertyInfo = type.GetProperty("PrintName", BindingFlags.Public | BindingFlags.Instance);
            var value = propertyInfo.GetValue(obj);
            if(value is Delegate @delegate)
            {
                @delegate.DynamicInvoke(new object[] {default});
            }
    class Student
    {
        public string Name { get; set; }
        class Course
        {
            public string Name { get; set; }
        }
        public Action<object> PrintName { get { return new Action<object>(e => { Console.WriteLine("这个是委托");}); } }
    }

 2.1获取执行静态方法

                Assembly assembly = Assembly.LoadFrom(程序集路径);
                Type type = assembly.GetType(命名空间.类名);
                MethodInfo method=type.GetMethod(方法名,BindingFlags.Static | BindingFlags.Public);
                method.Invoke(null, null);//静态方法的实例为null

备注

获取程序集资源文件,必须 过滤掉动态程序集

.Where(p => !p.IsDynamic)

 

反射判断类型是否是可以枚举的方法

            var parameter = new List<int>();

            var asga = parameter.GetType().GetInterface(typeof(IEnumerable<>).FullName);

            // 遍历类型实现的所有接口,判断是否存在某个接口是泛型,且是参数中指定的原始泛型的实例。
           var sgag= parameter.GetType().GetInterfaces().Any(x => typeof(IEnumerable<>) == (x.IsGenericType ? x.GetGenericTypeDefinition() : x));

 

反射方法创建委托

下面是官方的例子

        public delegate void D1(C c, string s);
        public delegate void D2(string s);
        public delegate void D3();

        public class C
        {
            private int id;
            public C(int id) { this.id = id; }

            public void M1(string s)
            {
                Console.WriteLine("Instance method M1 on C:  id = {0}, s = {1}",
                    this.id, s);
            }

            public static void M2(string s)
            {
                Console.WriteLine("Static method M2 on C:  s = {0}", s);
            }
        }
        static void Main(string[] args)
        {

            C c1 = new C(42);

            // Get a MethodInfo for each method.
            //
            MethodInfo mi1 = typeof(C).GetMethod("M1", BindingFlags.Public | BindingFlags.Instance);
            MethodInfo mi2 = typeof(C).GetMethod("M2", BindingFlags.Public | BindingFlags.Static);

            
            D1 d1;
            D2 d2;
            D3 d3;


            Console.WriteLine("\nAn instance method closed over C.");
            // In this case, the delegate and the
            // method must have the same list of argument types; use
            // delegate type D2 with instance method M1.
            //
            //委托与方法必须由相同的参数,使用实例方法创建委托
            Delegate test = Delegate.CreateDelegate(typeof(D2), c1, mi1, false);

            // Because false was specified for throwOnBindFailure 
            // in the call to CreateDelegate, the variable 'test'
            // contains null if the method fails to bind (for 
            // example, if mi1 happened to represent a method of  
            // some class other than C).
            //
            if (test != null)
            {
                d2 = (D2)test;

                // The same instance of C is used every time the 
                // delegate is invoked.
                d2("Hello, World!");
                d2("Hi, Mom!");
            }


            Console.WriteLine("\nAn open instance method.");
            // In this case, the delegate has one more 
            // argument than the instance method; this argument comes
            // at the beginning, and represents the hidden instance
            // argument of the instance method. Use delegate type D1
            // with instance method M1.
            //
            //委托的一个参数未实例,
            d1 = (D1)Delegate.CreateDelegate(typeof(D1), null, mi1);

            // An instance of C must be passed in each time the 
            // delegate is invoked.
            //
            d1(c1, "Hello, World!");
            d1(new C(5280), "Hi, Mom!");


            Console.WriteLine("\nAn open static method.");
            // In this case, the delegate and the method must 
            // have the same list of argument types; use delegate type
            // D2 with static method M2.
            //
            //使用静态方法的委托
            d2 = (D2)Delegate.CreateDelegate(typeof(D2), null, mi2);

            // No instances of C are involved, because this is a static
            // method. 
            //
            d2("Hello, World!");
            d2("Hi, Mom!");


            Console.WriteLine("\nA static method closed over the first argument (String).");
            // The delegate must omit the first argument of the method.
            // A string is passed as the firstArgument parameter, and 
            // the delegate is bound to this string. Use delegate type 
            // D3 with static method M2. 
            //
            //省略委托的第一个参数
            d3 = (D3)Delegate.CreateDelegate(typeof(D3),
                "Hello, World!", mi2);

            // Each time the delegate is invoked, the same string is
            // used.
            d3();

        }

创建委托

            var mi1 = typeof(C).GetMethod("M1");
            //委托类型,委托的第一个默认参数,方法
            Action<string> actionM1= (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), null, mi1);
            actionM1.Invoke("");

下面是关于属性转换为委托的测试

                {// 属性示例:public Action<object> Commod { get; set; } = new Action<object>(e => Console.WriteLine($"{e?.ToString()}你好"));

                    var info = frame.GetMethod().DeclaringType.GetProperties().Where(p => p.Name == "Commod" && typeof(Action<object>).IsAssignableFrom(p.PropertyType))
                        .FirstOrDefault();

                    //使用实例属性的GetGetMethod()创建Func委托,返回值为Action<object>
                    var proGetDel = Delegate.CreateDelegate(typeof(Func<Action<object>>), ribbonUI, info.GetGetMethod()) as Func<Action<object>>;
                    proGetDel.Invoke().Invoke("实例属性的Get访问器进行包装:--");

                    //第二个参数未null,将抛异常
                    //(Delegate.CreateDelegate(typeof(Func<Action<object>>), null, info.GetGetMethod()) as Func<Action<object>>)
                    //.Invoke().Invoke("GetGetMethod:--");

                    //直接调用实例属性的GetGetMethod()创建Func委托,返回值为Action<object>
                    (info.GetGetMethod().Invoke(ribbonUI, null) as Action<object>)
                    .Invoke("直接调用Get访问器:--");

                }

                {
                    //静态属性   public static Action<object> CommodSt { get; set; } = new Action<object>(e => Console.WriteLine($"{e?.ToString()}你好"));
                    var infoSt = frame.GetMethod().DeclaringType.GetProperties()
                        .Where(p => p.Name == "CommodSt" && typeof(Action<object>).IsAssignableFrom(p.PropertyType))
                        .FirstOrDefault();

                    //使用实例属性的GetGetMethod()创建Func委托,返回值为Action<object>
                    var proGetDel = Delegate.CreateDelegate(typeof(Func<Action<object>>), null, infoSt.GetGetMethod()) as Func<Action<object>>;
                    proGetDel.Invoke().Invoke("静态属性CommodSt的 Get访问器进行包装:--");

                    //直接调用静态属性的GetGetMethod()创建Func委托,返回值为Action<object>
                    (infoSt.GetGetMethod().Invoke(null,null) as Action<object>)
                    .Invoke("直接调用CommodSt属性的Get访问器:--");
                }

                {//lambda属性 public Action<object> CommodLambda  => e => Console.WriteLine($"{e?.ToString()}你好");
                    //其实就是实例方法
                    var info = frame.GetMethod().DeclaringType.GetProperties().Where(p => p.Name == "CommodLambda" && typeof(Action<object>).IsAssignableFrom(p.PropertyType))
                        .FirstOrDefault();

                    //使用实例属性的GetGetMethod()创建Func委托,返回值为Action<object>
                    var proGetDel = Delegate.CreateDelegate(typeof(Func<Action<object>>), ribbonUI, info.GetGetMethod()) as Func<Action<object>>;
                    proGetDel.Invoke().Invoke("实例属性的Get访问器进行包装:--");

                    //第二个参数未null,如果引用了实例的属性,将抛异常
                    (Delegate.CreateDelegate(typeof(Func<Action<object>>), null, info.GetGetMethod()) as Func<Action<object>>)
                    .Invoke().Invoke("GetGetMethod:--");

                    //直接调用实例属性的GetGetMethod()创建Func委托,返回值为Action<object>
                    (info.GetGetMethod().Invoke(ribbonUI, null) as Action<object>)
                    .Invoke("直接调用Get访问器:--");
                }

 判断是否为静态属性

                    if(info.GetGetMethod().IsStatic)
                    {

                    }

 

二、特性

内置常用特性标记

[Serializable] //标记序列化        
[DebuggerStepThrough] //标记调试跳过改方法 [Required] //标记值不能为空
      
//自定义特性的简单列子
  class AttributeTest
    {
        public void Test()
        {
            Type type = typeof(UseDemo);
            var customAttributes = type.GetCustomAttributes(true);
            foreach (var item in customAttributes)
            {
                var defindAttribute = item as DefindAttribute;
                if (defindAttribute != null)
                {
                    Console.WriteLine(defindAttribute.ShowInfo);
                }
            }
        }
    }
    [Defind("这是一个特性创建")]
    class UseDemo
    {
        public static void TestMain()
        {

        }
    }
    [AttributeUsage(AttributeTargets.Class)]//约束特性使用范围
    class DefindAttribute : Attribute
    {
        public DefindAttribute(string showInfo)
        {
            ShowInfo = showInfo;
        }
        public string ShowInfo { get; set; }
    }

 方法中获取被调用方法的调用堆栈,同时打印方法的属性标记的简单列子

    class Program
    {
        static void Main(string[] args)
        {
            TestAttribute testAttribute = new TestAttribute();
            testAttribute.MethodA();

            Console.Read();
        }
    }

    public class TestAttribute
    {
        [Remark("第一个方法")]
        public void MethodA() { BaseMethod(() => { Console.WriteLine("MethodA"); }); }

        private void BaseMethod(Action action)
        {
            var methodInfo = action.Method;
            StackTrace ss = new StackTrace(true);
            foreach (var frame in ss.GetFrames())
            {
                var attributes = frame.GetMethod().GetCustomAttributes();
                foreach (var attribute in attributes)
                {
                    if(attribute is RemarkAttribute remark)
                        Console.WriteLine(remark.Remark);
                }
            }

  
            action.Invoke();
        }
    }

    public class RemarkAttribute : Attribute
    {
        public string Remark { get; set; }
        public RemarkAttribute(string Remark)
        {
            this.Remark = Remark;
        }
    }

 给枚举添加特性标记的简单示例

    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
    public sealed class EnumDescriptionAttribute : Attribute
    {
        private string description;
        public string Description
        {
            get { return this.description; }
        }

        public EnumDescriptionAttribute(string description) : base()
        {
            this.description = description;
        }

        public static string GetDescription(Enum value)
        {
            if (value == null)
                throw new ArgumentNullException("value");

            System.Reflection.FieldInfo fieldinfo = value.GetType().GetField(value.ToString());

            var attribute = fieldinfo.GetCustomAttribute(typeof(EnumDescriptionAttribute), false);
            if (attribute is EnumDescriptionAttribute enumDescription)
                return enumDescription.Description;

            return string.Empty;
        }
    }

反射获取调用堆栈中的特性

/// <summary>
/// 获取调用堆栈中符合当前类型的特性 .Reverse()
/// 备注:字段与构造函数不会被获取
/// </summary>
/// <returns>null</returns>

public static IEnumerable<T> GetStackFramsCustomAttribute<T>() where T : Attribute
        {
            return new System.Diagnostics.StackTrace(true).GetFrames().Select(f => f.GetMethod())
                .Where(f => f.Name != ".ctor").SelectMany(method =>
                {
                    return method.DeclaringType.GetInterfaces()
                    .Select(t => t.GetMethod(method.Name))
                    .Where(t=>t!=null)
                    .SelectMany(t => t.GetCustomAttributes(typeof(T), true))
                    .Concat(Get());

                    IEnumerable<object> Get()
                    {
                        if (method.Name.Contains("<get_"))
                        {
                            var name = Regex.Match(method.Name, "(?<=get_).*(?=>)")?.Value;
                            var property = !string.IsNullOrWhiteSpace(name) ? (method.IsAssembly ? method.DeclaringType.DeclaringType : method.DeclaringType)
                            ?.GetProperty(name, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic
                            | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance) : null;

                            return (property?.GetCustomAttributes(typeof(T), false)) ?? Enumerable.Empty<object>();
                        }
                        else
                            return method.GetCustomAttributes(typeof(T), true);
                    }

                })
                .Cast<T>();
        }

 

 

自定义特性

    /// <summary>
    /// 控件名称标记的属性
    /// </summary>
    [SuppressSniffer, AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class ButtonNameRematkAttribute : Attribute
    {
        public ButtonNameRematkAttribute(object name)
        {
            Name = name;
        }
        public object Name { get; set; }
    }

使用示例,如果属性的写法是  public Action<object> ActionSet { get;},特性标记不会被读取到,所以修改了上面特性标记只能标记在方法上

    internal class Program
    {
        
        static void Main(string[] args)
        {


            GetAction.Invoke("");
            Console.WriteLine("Hello World!");
        }

        [ButtonNameRematkAttribute("静态: GetAction 属性")]
        static Action<object> GetAction { get { return e => ActionMethod.Invoke(""); } }


        static Action<object> ActionMethod = e => TestMethod();

        [ButtonNameRematkAttribute("静态: TestMethod 方法")]
        static void TestMethod()
        {
            Program program = new Program();
            program.Action.Invoke("");
        }
        [ButtonNameRematkAttribute("实例: Action 属性")]
        Action<object> Action { get { return e => InfoMain(); } }

        Action InfoMethod = () =>
        {
            var s = AttributeExtensions.GetStackFramsCustomAttribute<ButtonNameRematkAttribute>();
            foreach (var item in s)
                Console.WriteLine(item.Name);
        };

        [ButtonNameRematkAttribute("实例:InfoMain 方法")]
        void InfoMain()
        {
            InfoMethod.Invoke();
        }

        public Program()
        {

        }
    }

输出结果:

 

官方详细参考链接:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/attributes/

特性的创建和使用参考 https://www.cnblogs.com/chenxizhaolu/p/9497768.html

posted @ 2021-05-26 21:58  陆季疵  阅读(262)  评论(0编辑  收藏  举报
//《!--看板娘--> //https://www.cnblogs.com/ZTianming/p/14618913.html