精华内容
下载资源
问答
  • 反射和特性(2.反射特性信息)

    千次阅读 2016-12-30 15:56:44
    1.什么是特性特性是一个对象,它可以加载到程序集及程序集的对象中,这些对象包括 程序集本身、模块、类、接口、结构、构造函数、方法、方法参数等,加载了特性的对象称作特性的目标...后期参数越来越显然是使方法扩

    1.什么是特性

    特性是一个对象,它可以加载到程序集及程序集的对象中,这些对象包括 程序集本身、模块、类、接口、结构、构造函数、方法、方法参数等,加载了特性的对象称作特性的目标。特性是为程序添加元数据(描述数据的数据)的一种机制,通过它可以给编译器提供指示或者提供对数据的说明。

    2.使用FCL内置特性

    这是一个发送短信的示例,我们将短信需要的参数以方法参数的形式一个个代入方法。后期参数越来越多显然是使方法扩展性变得很糟糕。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestClass t = new TestClass();
                t.SendMsg("测试标题", "测试内容");
            }
        }
        public class TestClass
        {
            public void SendMsg(string title,string content)
            {
                Console.WriteLine("短信标题:{0}\n内容:{1}",title,content);
            }
        }
    }
    

    那么我们需要把参数封装成一个类作为参数传递给发送短信的方法

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestClass t = new TestClass();
                t.SendMsg(new Message() { title = "测试标题", content = "测试内容" });
            }
        }
        public class Message
        {
            public string title { get; set; }
            public string content { get; set; }
        }
        public class TestClass
        {
            public void SendMsg(Message msg)
            {
                Console.WriteLine("短信标题:{0}\n内容:{1}", msg.title, msg.content);
            }
            public void SendMsg(string title,string content)
            {
                Console.WriteLine("短信标题:{0}\n内容:{1}",title,content);
            }
        }
    }
    

    我们不能删除以前的SendMsg,否则会导致正在使用以前发送短信版本客户端程序出错,但是我们又想告知客户端程序员希望他们使用新版本的SendMsg怎么办呢??肯定不是电话或发邮件告知。接下来就使用特性来完成这件事,只要客户端使用旧版本,编译代码后由编译器告知

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestClass t = new TestClass();
                t.SendMsg("测试标题", "测试内容");
            }
        }
        public class Message
        {
            public string title { get; set; }
            public string content { get; set; }
        }
        public class TestClass
        {
            public void SendMsg(Message msg)
            {
                Console.WriteLine("短信标题:{0}\n内容:{1}", msg.title, msg.content);
            }
            [Obsolete("当前版本的发送短信不在进行维护,请使用新版SendMsg(Message msg)重载方法")]
            public void SendMsg(string title,string content)
            {
                Console.WriteLine("短信标题:{0}\n内容:{1}",title,content);
            }
        }
    }
    

    这里写图片描述

    输出窗口也可以看到编译警告,通过视图 》输出可以调出输出窗口

    3.自定义特性

    假设我们有这样一个很常见的需求:我们在创建或者更新一个类文件时,需要说明这个类是什么时候、由谁创建的,在以后的更新中还要说明在什么时候由谁更新的,可以记录也可以不记录更新的内容,以往你会怎么做呢?是不是像这样在类的上面给类添加注释:

    //更新:Matthew, 2008-2-10, 修改 ToString()方法
    //更新:Jimmy, 2008-1-18
    //创建:张子阳, 2008-1-15
    public class DemoClass{
        // Class Body
    }

    这样的的确确是可以记录下来,但是如果有一天我们想将这些记录保存到数据库中作以备份呢?你是不是要一个一个地去查看源文件,找出这些注释,再一条条插入数据库中呢?

    通过上面特性的定义,我们知道特性可以用于给类型添加元数据,这些元数据可以用于描述类型。那么在此处,特性应该会派上用场。那么在本例中,元数据应该是:注释类型(“更新”或者“创建”),修改人,日期,备注信息(可有可无)。而特性的目标类型是DemoClass类。

    按照对于附加到DemoClass类上的元数据的理解,我们先创建一个封装了元数据的类RecordAttribute:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
    
            }
        }
        public class RecordAttribute : Attribute
        {
            private string _recordType;//记录类型的定义:创建/更新
            private DateTime _date;//创建/更新 时间
            private string _author;//作者
            public string Remark { get; set; }//备注,命名参数,有get和set
    
            /// <summary>
            /// 档案记录,用于记录代码创建和更新的信息
            /// </summary>
            /// <param name="recordType">记录类型的定义:创建/更新</param>
            /// <param name="author">作者</param>
            /// <param name="date">创建/更新时间</param>
            public RecordAttribute(string recordType,string author,string date)
            {
                this._recordType = recordType;
                this._author = author;
                this._date = Convert.ToDateTime(date);
            }
            //对于位置参数只提供get
            public string RecordType { get { return _recordType; } }
            public DateTime Date { get { return _date; } }
            public string Author { get { return _author; } }
        }
    
    }
    

    注意构造函数的参数 date,必须为一个常量、Type类型、或者是常量数组,所以不能直接传递DateTime类型。否则:
    这里写图片描述

    3.1 使用自定义特性

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestClass t = new TestClass();
                Console.WriteLine(t.ToString());
            }
        }
        [Record("创建","张三","2016-12-30",Remark="这是第一次创建")]
        [Record("编辑", "李四", "2016-12-31", Remark = "新增了SendMsg方法")]
        public class TestClass
        {
            public override string ToString()
            {
                return "测试类";
            }
            public void SendMsg()
            {
                Console.WriteLine("SnedMsg");
            }
        }
    
        public class RecordAttribute : Attribute
        {
            private string _recordType;//记录类型的定义:创建/更新
            private DateTime _date;//创建/更新 时间
            private string _author;//作者
            public string Remark { get; set; }//备注,命名参数,有get和set
    
            /// <summary>
            /// 档案记录,用于记录代码创建和更新的信息
            /// </summary>
            /// <param name="recordType">记录类型的定义:创建/更新</param>
            /// <param name="author">作者</param>
            /// <param name="date">创建/更新时间</param>
            public RecordAttribute(string recordType,string author,string date)
            {
                this._recordType = recordType;
                this._author = author;
                this._date = Convert.ToDateTime(date);
            }
            //对于位置参数只提供get
            public string RecordType { get { return _recordType; } }
            public DateTime Date { get { return _date; } }
            public string Author { get { return _author; } }
        }
    
    }
    

    编译之后会出错,使用了重复的Record,问题是我们确实需要重复,代码在不断维护,记录也会随之重复增加。怎么办呢?
    我们观察系统内置特性Obsolete的定义,发现特性也有特性,这样的特性被称为 元元数据(meta-metadata),如:AttributeUsageAttribute

    3.2 AttributeUsageAttribute

    AttributeUsageAttribute有三个参数:

    ValidOn:获取一组值,这组值标识指示的属性可应用到的程序元素。

    AllowMultiple:获取或设置一个布尔值,该值指示能否为一个程序元素指定多个指示属性实例。

    Inherited:获取或设置一个布尔值,该值指示指示的属性能否由派生类和重写成员继承。

    Inherited设置为false,因为我不需要特性被子类继承,子类和父类不一定在同一时间修改,如这次更新版本只改了父类TestClass,并没有修改它的子类。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestClass t = new TestClass();
                Console.WriteLine(t.ToString());
            }
        }
        [Record("创建","张三","2016-12-30",Remark="这是第一次创建")]
        [Record("编辑", "李四", "2016-12-31", Remark = "新增了SendMsg方法")]
        public class TestClass
        {
            public override string ToString()
            {
                return "测试类";
            }
            public void SendMsg()
            {
                Console.WriteLine("SnedMsg");
            }
        }
        [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=true,Inherited=false)]
        public class RecordAttribute : Attribute
        {
            private string _recordType;//记录类型的定义:创建/更新
            private DateTime _date;//创建/更新 时间
            private string _author;//作者
            public string Remark { get; set; }//备注,命名参数,有get和set
    
            /// <summary>
            /// 档案记录,用于记录代码创建和更新的信息
            /// </summary>
            /// <param name="recordType">记录类型的定义:创建/更新</param>
            /// <param name="author">作者</param>
            /// <param name="date">创建/更新时间</param>
            public RecordAttribute(string recordType,string author,string date)
            {
                this._recordType = recordType;
                this._author = author;
                this._date = Convert.ToDateTime(date);
            }
            //对于位置参数只提供get
            public string RecordType { get { return _recordType; } }
            public DateTime Date { get { return _date; } }
            public string Author { get { return _author; } }
        }
    
    }
    

    4.通过反射获得特性信息

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace SimpleExplore
    {
        class Program
        {
            static void Main(string[] args)
            {
                Type t = typeof(TestClass);
    
                Console.WriteLine("下面列出应用于 TestClass 的RecordAttribute属性:", t.ToString());
    
                foreach (RecordAttribute item in t.GetCustomAttributes(typeof(RecordAttribute), false))
                {
                    Console.WriteLine(item.ToString());
                    Console.WriteLine("      类型:{0}", item.RecordType);
                    Console.WriteLine("      作者:{0}", item.Author);
                    Console.WriteLine("      日期:{0}", item.Date.ToString("yyyy-MM-dd"));
                    if (!String.IsNullOrEmpty(item.Remark))
                    {
                        Console.WriteLine("      备注:{0}", item.Remark);
                    }
                } 
            }
        }
        [Record("创建","张三","2016-12-30",Remark="这是第一次创建")]
        [Record("编辑", "李四", "2016-12-31", Remark = "新增了SendMsg方法")]
        public class TestClass
        {
            public override string ToString()
            {
                return "测试类";
            }
            public void SendMsg()
            {
                Console.WriteLine("SnedMsg");
            }
        }
        [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=true,Inherited=false)]
        public class RecordAttribute : Attribute
        {
            private string _recordType;//记录类型的定义:创建/更新
            private DateTime _date;//创建/更新 时间
            private string _author;//作者
            public string Remark { get; set; }//备注,命名参数,有get和set
    
            /// <summary>
            /// 档案记录,用于记录代码创建和更新的信息
            /// </summary>
            /// <param name="recordType">记录类型的定义:创建/更新</param>
            /// <param name="author">作者</param>
            /// <param name="date">创建/更新时间</param>
            public RecordAttribute(string recordType,string author,string date)
            {
                this._recordType = recordType;
                this._author = author;
                this._date = Convert.ToDateTime(date);
            }
            //对于位置参数只提供get
            public string RecordType { get { return _recordType; } }
            public DateTime Date { get { return _date; } }
            public string Author { get { return _author; } }
        }
    
    }
    

    这里写图片描述

    展开全文
  • C# 反射特性简介

    千次阅读 2017-10-24 14:10:27
    1.程序是用来处理数据的,文本和特性都是数据,而我们程序本身(类的定义和BLC中的类)这些也是数据。 2.有关程序及其类型的数据被称为元数据(metadata),它们保存在程序的程序集中。 程序在运行时,可以查看其它...

    什么是元数据和反射???
    1.程序是用来处理数据的,文本和特性都是数据,而我们程序本身(类的定义和BLC中的类)这些也是数据。
    2.有关程序及其类型的数据被称为元数据(metadata),它们保存在程序的程序集中。
    程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射。

    下面我们我们来学习如何使用Type类来反射数据,以及如何使用特性来给类型添加元数据。
    Type位于System.Reflection命名空间下

    Type类:
    预定义类型(int long 和string等),BCL中的类型(Console,IEnumerable等)和程序员自定义类型(MyClass,MyDel等)。 每种类型都有自己的成员和特性。
    BCL声明了一个叫做Type的抽象类,它被设计用来包含类型的特性。使用这个类的对象能让我们获取程序使用的类型的信息。
    由于 Type是抽象类,因此不能利用它去实例化对象。关于Type的重要事项如下:
    对于程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象。
    程序中用到的每一个类型都会关联到独立的Type类的对象。
    不管创建的类型有多少个示例,只有一个Type对象会关联到所有这些实例。
    Type是使用示例:

    using System;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Reflection;
    
    namespace _002_反射
    {
        class Program
        {
            static void Main(string[] args)
            {
                //每一个类对应一个type对象,,这个对象存储了这个类,有哪些方法,成员
                Text mytext = new Text();    //类中的数据是存储在对象中的,type之存储类的成员
    
                //通过对象获取对象所属类的Type的对象
                Type type = mytext.GetType();   
    
                Console.WriteLine(type.Name);       //获取类名
                Console.WriteLine(type.Namespace);  //所在命名空间
                Console.WriteLine(type.Assembly);   //程序集
    
                //获取方法中所有公有的(public)字段
                Console.WriteLine();
                Console.WriteLine("========公有字段=========");
                FieldInfo[] infoarr = type.GetFields();
                foreach (FieldInfo item in infoarr)
                {
                    Console.Write(item.Name + " ");
                }
    
                //获取所有的公有属性
                Console.WriteLine();
                Console.WriteLine("========公有属性=========");
                PropertyInfo[] properarr = type.GetProperties();
                foreach (PropertyInfo info in properarr)
                {
                    Console.Write(info.Name + " ");
                }
    
                //获取所有的公有方法
                Console.WriteLine();
                Console.WriteLine("========公有方法=========");
                MethodInfo[] methodarr = type.GetMethods();
                foreach (MethodInfo info in methodarr)
                {
                    Console.Write(info.Name + " ");
                }
    
                Console.ReadKey();
            }
        }
    }

    测试用的Text类

    namespace _002_反射
    {
        class Text
        {
            private int id;
            public int age;
            public int num;
    
            public string Name { get; set; }
            public string Age { get; set; }
            public string Sex { get; set; }
    
            public void Test1()  {}
            public void Text2()    { }
        }
    }

    运行结果图:
    1


    Assembly 类: (Text类使用的还是上面的那个)
    如何加载程序集?
    1,Assembly assembly1 = Assembly.Load(“SomeAssembly”);根据程序集的名字加载程序集,它会在本地目录和全局程序集缓存目录查找符合名字的程序集。
    2,Assembly assembly2 = Assembly.LoadFrom(@”c:\xx\xx\xx\SomeAssembly.dll”)//这里的参数是程序集的完整路径名,它不会在其他位置搜索。

    using System;
    using System.Reflection;
    
    namespace _002_反射
    {
        class Program
        {
            static void Main(string[] args)
            {
                Text mytext = new Text();
                //通过类的type对象获取它所在的程序集
                Assembly assem = mytext.GetType().Assembly;
                Console.WriteLine("完整的名字:"+ assem.FullName);
    
                Type[] type = assem.GetTypes();
                foreach (var item in type)
                {
                    Console.WriteLine(item);
                }
                //源码编译就会出来.exe文件和一些配置文件,即程序集,,
                Console.ReadKey();
            }
        }
    }

    特性:
    特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
    将应用了特性的程序结构叫做目标
    设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者
    .NET预定了很多特性,我们也可以声明自定义特性

    [ Obsolete]示例
    namespace _003_特性
    {
        class Program
        {
            static void Main(string[] args)
            {
                // 当 [Obsolete ("此方法已过时,请使用NewFun"),ture] 调用会出编译错误   
                // OldFun();
    
                //若不写第二个参数,,则会画波浪线做出提示,且方法可用
                OldFun();
            }
            //通过这个特性表示一个方法已经被弃用了,(但是还能使用下面会有波浪线做标识)
            [Obsolete ("此方法已过时,请使用NewFun")]   
            static void OldFun()
            {
                Console.WriteLine("OldFun");
            }
    
            static void NewFun()
            {
    Console.WriteLine("NewFun");
            }
        }
    }

    Conditional特性:
    Conditional特性允许我们包括或取消特定方法的所有调用。为方法声明应用Conditional特性并把编译符作为参数来使用。
    定义方法的CIL代码本身总是会包含在程序集中,只是调用代码会被插入或忽略。

    应用示例:

    #define Method1   //定义一个宏,控制Method1()是否被调用,若不存在则所有的Method1() 都不会调用
    
    using System;
    using System.Diagnostics;     //命名空间
    
    namespace _003_特性
    {
        class Program
        {
            static void Main(string[] args)
            {
                //模拟多次调用方法,,,如果想取消调用method1() 就会变得麻烦
                Method1();
                Method2();
                Method1();
    
                Console.ReadKey();
            }
    
            [Conditional("Method1")]
            static void Method1()
            {
                Console.WriteLine("Method1");
            }
            static void Method2()
            {
                Console.WriteLine("Method2");
            }
        }
    }

    调用者信特性:
    调用者信息特性可以访问文件路径,代码行数,调用成员的名称等源代码信息。
    1.这个三个特性名称为CallerFilePath,CallerLineNumber和CallerMemberName
    2.这些特性只能用于方法中的可选参数

    using System;
    using System.Runtime.CompilerServices;
    
    namespace _003_特性
    {
        class Program
        {
            static void Main(string[] args)
            {
                DebugLog("Czhenya");
    
                Console.ReadKey();
            }
    
            static void DebugLog(string str,[CallerFilePath]string fileName = "",
                [CallerLineNumber]int lineNumber = 0,
                [CallerMemberName]string methodName = "")
            {
                Console.WriteLine("用户输入的参数:"+str);
                Console.WriteLine("调用的目录:"+fileName);
                Console.WriteLine("在第{0}行调用的",lineNumber);
                Console.WriteLine("在{0}方法中调用的",methodName);
            }
        }
    }

    2

    DebuggerStepThrough 特性
    单步调试代码的时候,常常希望调试器不要进入某些方法。我们只想执行该方法,然后继续调试下一行。DebuggerStepThrough特性告诉调试器在执行目标代码时不要进入该方法调试。有些方法小并且毫无疑问是正确的,在调试时对其反复单步调试只能徒增烦恼。要小心使用该特性,不要排除了可能出现bug的代码。
    [DebuggerStepThrough] //跳过这个方法的但不测试,当确定此方法无任何错误的时候可以使用,,,


    自定义特性类:
    声明一个特性类和声明其他类一样。有下面的注意事项
    声明一个派生自System.Attribute的类
    给它起一个以后缀Attribute结尾的名字
    (安全起见,一般我们声明一个sealed的特性类)
    特性类声明如下:
    public sealed class MyAttribute : System.Attribute{

    特性类的公共成员可以是
    字段
    属性
    构造函数

    AttributeTarget枚举的成员
    All Assembly Class Constructor Delegate Enum Event Field
    GenericParameter Interface Method Module Parameter Property ReturnValue Struct
    多个参数之间使用按位或|运算符来组合
    AttributeTarget.Method|AttributeTarget.Constructor

    自定义特性类一般遵循的规则:
    特性类应该表示目标结构的一些状态
    如果特性需要某些字段,可以通过包含具有位置参数的构造函数来收集数据,可选字段可以采用命名参数按需初始化
    除了属性之外,不要实现公共方法和其他函数成员
    为了更安全,把特性类声明为sealed
    在特性声明中使用AttributeUsage来指定特性目标组

    using System;
    namespace _003_特性
    {
        // 特性类,后缀以Attribute结尾
        // 需要继承自System.Attibute
        // 一般声明为sealed
        // 一般情况下特性类用来表示目标结构的一些状态,定义一些字段,属性,不定义方法
    
        [AttributeUsage(AttributeTargets.Class)]   //表示该特性类可以使用的结构有哪些
        sealed class MyAttribute : Attribute
        {
            public string Desctiption { get; set; }
            public string VersionNumber { get; set; }
            public int ID { get; set; }
    
            //构造函数
            public MyAttribute(string str)
            {
                this.Desctiption = str;
            }
    
        }
    }
    
    using System;
    namespace _003_特性
    {
        //通过制定属性的名字,给属性赋值,这种就是命名参数
        [My("自定义的特性类", ID=111)]   //使用特性的时候,后面的Attribute不用写
        class Program
        {
            static void Main(string[] args)
            {
                //通过typeof(类名) 也可创建type对象
                Type type = typeof(Program);
    
                object[] objarr = type.GetCustomAttributes(false);
                //获取本类使用到的特性
                MyAttribute my = objarr[0] as MyAttribute;
    
                Console.WriteLine(my.Desctiption+"\n ID : "+my.ID);
    
                Console.ReadKey();
            }
        }
    }
    展开全文
  • C#反射特性

    千次阅读 2015-09-27 22:39:24
    C#反射特性 1、Type类 预定义类型(int long和string等),BCL中的类型(Console,IEnumerable等)和程序员自定义类型(MyClass,MyDel等)。 每种类型都有自己的成员和特性。 BCL声明了一个叫做Type的抽象类,它被设计...

    C#反射和特性

    1、Type类

    预定义类型(int long和string等),BCL中的类型(Console,IEnumerable等)和程序员自定义类型(MyClass,MyDel等)。 每种类型都有自己的成员和特性。
    BCL声明了一个叫做Type的抽象类,它被设计用来包含类型的特性。使用这个类的对象能让我们获取程序使用的类型的信息。
    由于 Type是抽象类,因此不能利用它去实例化对象。关于Type的重要事项如下:
    对于程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象。
    程序中用到的每一个类型都会关联到独立的Type类的对象。
    不管创建的类型有多少个示例,只有一个Type对象会关联到所有这些实例。

    System.Type类部分成员:


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    
    namespace _014_反射和特性 {
        class MyClass
        {
            private int id;
            private int age;
            public int number;
            public string Name { get; set; }
            public string Name2 { get; set; }
            public string Name3 { get; set; }
    
            public void Test1() {
    
            }
            public void Test2() {
    
            }
        }
    }
    

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _014_反射和特性 {
        class Program {
            static void Main(string[] args) {
                //每一个类对应一个type对象,这个type对象存储了这个类 有哪些方法跟哪些数据 哪些成员
                //MyClass my = new MyClass();//一个类中的数据 是存储在对象中的, 但是type对象只存储类的成员
                //Type type = my.GetType();//通过对象获取这个对象所属类 的Type对象
                //Console.WriteLine(type.Name);//获取类的名字
                //Console.WriteLine(type.Namespace);//获取所在的命名空间
                //Console.WriteLine(type.Assembly);
                //FieldInfo[] array= type.GetFields();//只能获取public 字段
                //foreach (FieldInfo info in array)
                //{
                //    Console.Write(info.Name+" ");
                //}
                //PropertyInfo[] array2 = type.GetProperties();
                //foreach (PropertyInfo info in array2)
                //{
                //    Console.Write(info.Name+" ");
                //}
                //MethodInfo[] array3 = type.GetMethods();
                //foreach (MethodInfo info in array3)
                //{
                //    Console.Write(info.Name+" ");
                //}
                //通过type对象可以获取它对应的类的所有成员(public)
    
                MyClass my = new MyClass();
                Assembly assem =  my.GetType().Assembly;//通过类的type对象获取它所在的程序集 Assembly
                Console.WriteLine(assem.FullName);
                Type[] types = assem.GetTypes();
                foreach (var type in types)
                {
                    Console.WriteLine(type);
                }
                Console.ReadKey();
            }
        }
    }
    


    2、特性

    特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
    将应用了特性的程序结构叫做目标。
    设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者。
    .NET预定了很多特性,我们也可以声明自定义特性。

    Obsolete特性:

    class Program{
    	[Obsolete("Use method SuperPrintOut")]	//将特性应用到方法
    	static void PrintOut(string str){
    		Console.WriteLine(str);
    	}
    	[Obsolete("Use method SuperPrintOut",true)]//这个特性的第二个参数表示是是否应该标记为错误,而不仅仅是警告。
    	static void PrintOut(string str){
    		Console.WriteLine(str);
    	}
    	static void Main(string[] args){
    		PrintOut("Start of Main");
    	}
    }
    

    Conditional特性:

    class Program{
    	[Conditional("DoTrace")] 
    	static void TraceMessage(string str){
    		Console.WriteLine(str);
    	}
    	static void Main(){
    		TraceMessage("Start of Main");
    		Console.WriteLine("Doing work in Main.")
    		TraceMessage("End of Main");
    	}
    }
    

    调用者信息特性:

    DebuggerStepThrough特性:

    简单示例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
    
    namespace _015_特性 {
        //1, 特性类的后缀以Attribute结尾 
        //2, 需要继承自System.Attribute
        //3, 一般情况下声明为 sealed
        //4, 一般情况下 特性类用来表示目标结构的一些状态(定义一些字段或者属性, 一般不定义方法)
        [AttributeUsage(AttributeTargets.Class)]//表示该特性类可以应用到的程序结构有哪些
        sealed class MyTestAttribute : System.Attribute {
            public string Description { get; set; }
            public string VersionNumber { get; set; }
            public int ID { get; set; }
    
            public MyTestAttribute(string des)
            {
                this.Description = des;
            }
        }
    }
    

    #define IsTest //定义一个宏
    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _015_特性 {
        //通过制定属性的名字,给属性赋值,这种事命名参数
        [MyTest("简单的特性类",ID = 100)]//当我们使用特性的时候,后面的Attribute不需要写
        class Program {
            [Obsolete("这个方法过时了,使用NewMethod代替")] //obsolete特性用来表示一个方法被弃用了
            static void OldMethod()
            {
                Console.WriteLine("Oldmethod");
            }
    
            static void NewMethod()
            {
                
            }
            [Conditional("IsTest")]
            static void Test1() {
                Console.WriteLine("test1");
            }
            static void Test2() {
                Console.WriteLine("test2");
            }
    
            [DebuggerStepThrough]//可以跳过debugger 的单步调试 不让进入该方法(当我们确定这个方法没有任何错误的时候,可以使用这个)
            static void PrintOut(string str,[CallerFilePath] string fileName="",[CallerLineNumber] int lineNumber=0,[CallerMemberName] string methodName ="")
            {
                Console.WriteLine(str);
                Console.WriteLine(fileName);
                Console.WriteLine(lineNumber);
                Console.WriteLine(methodName);
            }
            static void Main(string[] args) {
                //NewMethod();
                //OldMethod();
                //Console.ReadKey();
    
                //Test1();
                //Test2();
                //Test1();
    
                //PrintOut("123");
    
                Type type = typeof(Program);//通过typeof+类名也可以获取type对象
                object[] array = type.GetCustomAttributes(false);
                MyTestAttribute mytest = array[0] as MyTestAttribute;
                Console.WriteLine(mytest.Description);
                Console.WriteLine(mytest.ID);
                Console.ReadKey();
            }
        }
    }

    ===================================================================================
    结束。

    展开全文
  • C#特性反射机制

    2016-03-05 12:43:50
    C#特性反射机制大纲 特性 预定义特性 AttributeUsage Conditional Obsolete 自定义特性 反射机制 特性什么是特性特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。 特性的...

    C#特性与反射机制

    大纲

    • 特性
      • 预定义特性
      • AttributeUsage
      • Conditional
      • Obsolete
      • 自定义特性
    • 反射机制

    特性

    什么是特性?

    特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。

    特性的语法

    [attribute(positional_parameters, name_parameter = value, ...)]
    element
    

    特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

    预定义特性

    AttributeUsage

    预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。
    语法

    [AttributeUsage(
       validon,
       AllowMultiple=allowmultiple,
       Inherited=inherited
    )]

    其中,

    • 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All
    • 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
    • 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。

    例如,

    [AttributeUsage(AttributeTargets.Class)]
    class SthAttribute: Attribute{} //自定义特性

    Conditional

    这个预定义特性标记了一个条件方法,其执行依赖于它顶的预处理标识符。
    语法

    [Conditional(
       conditionalSymbol
    )]

    Obsolete

    这个预定义特性标记了一个条件方法,其执行依赖于它顶的预处理标识符。
    语法

    [Obsolete(
       message
    )]
    [Obsolete(
       message,
       iserror
    )]

    其中,
    - 参数 message,是一个字符串,描述项目为什么过时的原因以及该替代使用什么。
    - 参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。


    创建自定义特性

    创建并使用自定义特性包含四个步骤:

    • 声明自定义特性
    • 构建自定义特性
    • 在目标程序元素上应用自定义特性
    • 通过反射访问特性

    声明自定义特性例子,

    public class TableAttribute: Attribute{} //特性必须是Attribute的派生类

    构建自定义特性例子,

    public class TableAttribute: Attribute{
        public string TableName{
            get;
            set;
        }
        ...
    }

    在目标程序元素上应用自定义特性例子,

    [TableAttribute(TableName="department")]
    public class Department{
        //...
    }

    通过反射访问特性
    例子,

    var obj = new Department();
    #region process
    ...
    #endregion
    var ta = Attribute.GetCustomAttribute(obj.GetType(), typeof(TableAttribute)) as TableAttribute;

    反射机制

    什么是反射?

    反射(Reflection) 对象用于在运行时获取类型信息。

    反射(Reflection)有下列用途
    - 它允许在运行时查看属性(attribute)信息。
    - 它允许审查集合中的各种类型,以及实例化这些类型。
    - 它允许延迟绑定的方法和属性(property)。
    - 它允许在运行时创建新类型,然后使用这些类型执行一些任务。

    查看属性
    NewClassw nc = new NewClassw();
    Type t = nc.GetType();
    // get the public properties
    PropertyInfo[] pis = t.GetProperties();
    foreach(PropertyInfo pi in pis)
    {
        Console.WriteLine(pi.Name); //output the public property name
    }
    
    // get the public methods
    MethodInfo[] mis = t.GetMethods();
    foreach (MethodInfo mi in mis)
    {
        Console.WriteLine(mi.ReturnType+" "+mi.Name);
    }
    实例化
    NewClassw nc = new NewClassw();
    Type t = nc.GetType();
    object obj = Activator.CreateInstance(t);
    //取得ID字段
    FieldInfo fi = t.GetField("ID");
    //给ID字段赋值
    fi.SetValue(obj, "k001");
    //取得MyName属性
    PropertyInfo pi1 = t.GetProperty("MyName");
    //给MyName属性赋值
    pi1.SetValue(obj, "grayworm", null);
    PropertyInfo pi2 = t.GetProperty("MyInfo");
    pi2.SetValue(obj, "hi.baidu.com/grayworm", null);
    //取得show方法
    MethodInfo mi = t.GetMethod("show");
    //调用show方法
    mi.Invoke(obj, null);
    延迟绑定的方法和属性
    Student nc = new Student();
    Type t= nc.GetType();
    //获取NewClass所有属性
    PropertyInfo[] pis = t.GetProperties();
    //从数据库中获取Student表
    DataTable dt = SqlHelper.ExecuteDataTable("SELECT * FROM Student WHERE ID=@ID", new SqlParameter("@ID", studentID));
    foreach(PropertyInfo pi in pis)
    {
        pi.SetValue(nc,pi.Name,dt.rows[0][pi.Name])
    }
    

    相关链接:

    特性参考链接

    反射机制参考链接

    展开全文
  • 反射特性; 元数据和反射; Type类; 获取Type对象; 什么是特性; 应用特性; 预定义的保留的特性; 有关应用特性的更内容; 自定义特性; 访问特性
  • C#反射特性

    千次阅读 2013-04-03 23:59:46
    什么是反射 反射特性(Attribute) 1. C#内置特性介绍 特性是一个对象,它可以加载到程序集及程序集的对象中,这些对象包括 程序集本身、模块、类、接口、结构、构造函数、方法、方法参数等,加载了特性的对象称作...
  • 特性类似于代码注释,但特性能从程序中通过反射获取,注释是获取不到的建一个类People.cs里面创建2个属性 public class People { public int Id { get; set; } public string name { get; set; } }然后建立一个...
  • C#反射特性,数据库结合使用

    千次阅读 2016-04-25 15:23:17
    C#反射特性,数据库结合使用
  • Type t=typeof(double);
  • 重新整理反射--特性

    千次阅读 2014-07-28 22:24:23
    特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性特性的应用    (1).net中特性用来处理多种问题,比如序列化、程序的安全特性、防止即时编译器对程序代码进行优化从而代码容易调试等等...
  • C# Assembly反射特性

    千次阅读 2016-10-20 20:57:59
    使用反射可以看到一个程序集内部的接口、类、方法、字段、属性、特性等等信息。 什么是Assembly(程序集)?  Assembly是一个包含来程序的名称,版本号,自我描述,文件关联关系和文件位置等信息的一个集合。在...
  • Java高级特性反射

    千次阅读 2020-01-23 17:22:11
    Java高级特性——反射 原文链接 定义 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的...
  • 标准C++实现反射特性

    千次阅读 2010-03-17 13:03:00
    众多优秀的特性中,我觉得反射,对于系统设计影响极为重大,一个系统是否支持反射 (Reflection) ,甚至会决定系统体系构架。比如在 Reflection 体系下,实现远程调用( RPC )就会很顺畅,而 .net 让 GUI 变得无比...
  • Java语言为什么提供反射特性

    千次阅读 2013-11-10 23:54:37
    不久前看java编程思想,突然想到为什么java会提供反射机制这个问题。在面向对象的编程思想里,访问权限控制是必须的,如java也通过设计private protected public以及默认包访问等不断的细化访问权限,但,为什么java...
  • Java核心特性反射机制

    千次阅读 2021-03-18 00:09:53
    1、反射概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java...
  • php高级特性-反射

    千次阅读 2016-11-30 22:24:10
    一、什么是反射?它是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取的信息以及动态调用对象的方法的功能称为反射API。 反射是操纵面向对象范型...
  • C#自定义特性反射

    千次阅读 2015-10-11 16:18:49
    反射需要一整本书来讨论,这里只介绍了Type类和Assembly类,他们是访问反射所提供的拓展功能的主要入口点。这里介绍了自定义特性,它比其它方面更常用,以及如何在运行期间检索自定义特性信息。 一、自定义特性 ...
  • C#中的反射特性

    2018-05-30 15:03:56
    程序是用来处理数据的,文本和特性都是数据;而程序本身(类的定义和BLC中类)这些也都是数据。 有关程序以及其类型的数据被称为元数据(metadata),他们保存在程序的程序集中。 程序在运行时,可以查看其它程序集...
  • C#笔记(反射特性

    千次阅读 2018-04-11 16:07:14
    1 反射 ...每一个类型都有自己的成员和特性,BCL声明了一个 Type 抽象类,它用来包含类型的特性,即使用 Type 类可以反射数据。 对于程序中用到的每个类型,CLR都会创建一个包含这个类型信息的 T...
  • C#反射读取类定制特性信息

    千次阅读 2013-10-16 13:00:20
    此项目又分为3个小项目: 1.WhatsNewAttributes类库...3.Checker控制台应用程序:用反射读取myClass中的公共成员方法,以及定制特性   因此:myClass类库需引入WhatsNewAttributes类库编译的DLL文件  

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 128,204
精华内容 51,281
关键字:

多向反射特性