(16)反射、特性和动态编程

 

**反射:是在在一个程序集中的元数据进行检查的过程。除此之外,可以利用反射枚举程序集中的所有类型,并搜索满足特定条件的那些类型。通过System.type的实例来访问一个类型的元数据。

利用反射,可以访问程序集中的元数据,使用元数据,在运行时动态调用一个类型的成员,而不是在执行编译时绑定。

**使用

System.Type访问元数据。

Type.Name

Type.IsPublic

Type.BaseType

Type.GetInterfaces()

Type.Assembly:类型是在哪个程序集中定义的。

Type.GetProperties()

Type.GetMethod()

Type.GetFileds()

Type.GetCustomAttributes():都有什么特性在修饰一个类型....

**GetType():object的方法

使用GetType()的关键是活的对象实例。静态类是无法实例化的,所以没有办法调用GetType()

            DateTime datetime = new DateTime();
            Type type = datetime.GetType();
             foreach(System.Reflection.PropertyInfo property in type.GetProperties())
            {
                Console.WriteLine(property.Name);
            }
       /*  Date
           Day
           DayOfWeek
           DayOfYear
           Hour
           Kind
           Millisecond
           Minute
           Month
           Now
           UtcNow
           Second
           Ticks
           TimeOfDay
           Today
           Year
        */

*typeof()方法在编译时绑定到一个特定的Type实例。

            //使用typeof()创建一个System.Type()实例
             ThreadPriorityLevel priority;
             priority = (ThreadPriorityLevel)Enum.Parse(typeof(ThreadPriorityLevel),"Idle");

**动态成员调用【还不是很理解,先放着疑问

                    PropertyInfo property =
                        commandLine.GetType().GetProperty(option, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
                    if (property != null)
                    {
                        if (property.PropertyType == typeof(bool))
                        {
                            //last parameters for handong indexers
                            property.SetValue(commandLine,true,null);
                            success = true;
                        }
                        else if(property.PropertyType==typeof(string))
                        {
                            property.SetValue(commandLine,optionParts[1],null);
                            success = true;
                        }
                        else if (property.GetType().IsEnum)
                        {
                            try
                            {
                                property.SetValue(commandLine, Enum.Parse(typeof(ProcessPriorityClass), optionParts[1], true), null);

                            }

**泛型上的反射

在泛型类型上执行运行时反射,将判断出一个类或方法是否包含泛型类型,并确定它包含的任何类型参数。

1.判断类型参数的类型,获得Type 的对象实例后,就可以在类型参数上执行反射,从而判断它的行为,并针对具体类型来调整方法,使其更有效的支持这种方法。

public class stack<T>

{

...

public void Add(T t)

{

Type t= typeof(T);

}

}
2.判断类或方法是否支持泛型

            Type type;
            type=typeof(System.Nullable<>);
            //type.ContainsGenericParameters:判断类或方法是否包含未设置的参数。
            Console.WriteLine(type.ContainsGenericParameters);
            Console.WriteLine(type.IsGenericType);

            type=typeof(System.Nullable<DateTime>);
            Console.WriteLine(!type.ContainsGenericParameters);
            //判断当前类型是否是泛型类型。
            Console.WriteLine(type.IsGenericType);
           /* True
            True
            True
            True*/

3.为泛型类或方法获取类型参数:可以调用GetGenericArguments()方法,从一个泛型类型获取泛型实参或(类型参数)的一个类表。这样得到的是一个System.Type实例构成的一个数组,其顺序与泛型类参数顺序一致。

            Dictionary<int,string> d=new Dictionary<int,string>();
            Type t = d.GetType();
            foreach (Type type in t.GetGenericArguments())
            {
                System.Console.WriteLine("Type parameter:" +type.FullName);
            }
            //Type parameter:System.Int32
            //Type parameter:System.String

**特性(Attribute):利用特性,我们可以指定与被修饰的构造有关的额外元数据。使用特性,可以将一个属性修饰为Required(必要)的,并提供一个/?选项别名。换言之,特性是将数据额外关联到一个属性(以及其他构造的)一种方式。

特性要放到他们修饰的那个构造之前的一对方括号中。

特性不适用于返回值、程序集和模块。
//可以用多个特型来修饰属性,用多个分开的[ ]或者一个[ , ]来修饰。

    private class CommandLineInfo
    {
        [CommandLineSwitchAlias("?")]
        [CommandLineSwitchRequired]
        public bool Help { get; set; }

        [CommandLineSwitchAlias("FileName"),
        CommandLineSwitchRequired]
        public string Out { get; set; }

        public ProcessPriorityClass Priority
        {
            get { return _Priority; }
            set { _Priority = value; }
        }
        private ProcessPriorityClass _Priority = ProcessPriorityClass.Normal;
    }

*程序集特性用于添加有关程序集的额外元数据。

例如:

// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Ex16_04")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Ex16_04")]
[assembly: AssemblyCopyright("Copyright ©  2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

*制定一个return 特性:[return:],除此之外,还有module: class: method:等目标。其中class:和method:是可选的。

**自定义特性:定义一个类,从System.Attribute派生之后,一个普通的类就成为了一个特性。

public class CommandLineSwitchRequiredAttribute:Attribute

{

}

*获取一个自定义特性

        public static string[] GetMissingRequiredOptions(object commandLine)
        {
            StringCollection missingOptions = new StringCollection();
            //利用反射来获取实例
            PropertyInfo[] properties = commandLine.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                //用GetCustomAttributes()指定要查找的特性,并指定是否检查任何重载的方法。另外,也可以使用GetCustomAttributes()方法而不指定特性类型。
                Attribute[] attributes = (Attribute[])property.GetCustomAttributes(typeof(commandLineInfoAttribute), false);
                if ((attributes.Length > 0) && (property.GetValue(commandLine, null) == null))
                {
                    if (property.GetValue(commandLine, null) == null)
                    {
                        missingOptions.Add(property.Name);
                    }
                }
             //...
            }
           //...;
        } 

学习MSDN上的例子比较清楚

using System;
using System.Reflection;

namespace CustomAttrCS
{
    // An enumeration of animals. Start at 1 (0 = uninitialized).
    public enum Animal
    {
        // Pets.
        Dog = 1,
        Cat,
        Bird,
    }

    // A custom attribute to allow a target to have a pet.
    public class AnimalTypeAttribute : Attribute
    {
        // The constructor is called when the attribute is set.
        //构造器的参数只有字面值和类型(typeof(int))
        //
        public AnimalTypeAttribute(Animal pet)
        {
            thePet = pet;
        }

        // Keep a variable internally ...
        protected Animal thePet;

        // .. and show a copy to the outside world.
        public Animal Pet
        {
            get { return thePet; }
            set { thePet = Pet; }
        }
    }

    // A test class where each method has its own pet.
    //特性作用在方法上
    class AnimalTypeTestClass
    {
        [AnimalType(Animal.Dog)]  //添加特性,匹配与特性的构造器
        public void DogMethod() { }

        [AnimalType(Animal.Cat)]
        public void CatMethod() { }

        [AnimalType(Animal.Bird)]
        public void BirdMethod() { }
    }

    class DemoClass
    {
        static void Main(string[] args)
        {
            //特性作用在方法上:
            AnimalTypeTestClass testClass = new AnimalTypeTestClass();
            Type type = testClass.GetType();//反射
            // Iterate through all the methods of the class.
            foreach (MethodInfo mInfo in type.GetMethods())
            {
                // Iterate through all the Attributes for each method.
                foreach (Attribute attr in
                    Attribute.GetCustomAttributes(mInfo))
                {
                    // Check for the AnimalType attribute.
                    if (attr.GetType() == typeof(AnimalTypeAttribute))
                        Console.WriteLine(
                            "Method {0} has a pet {1} attribute.",
                            mInfo.Name, ((AnimalTypeAttribute)attr).Pet);
                }
            }

            //特性作用在属性上
            //PropertyInfo property = typeof(className).GetProperties("help");
            //classNameAttribute attribute=(classNameAttribute)property.GetCustomAttributes(typeof(classNameAttribute),false);
            //...

            Console.ReadKey();
        }
    }
}

**疑问特性的其他知识,不是很理解P511-P526【留着研究下:】


           

 **使用动态对象编程

使用动态对象编程,开发人员可以用一个动态调用机制对摄像的操作进行编码。“运行时”会对程序执行时对这个机制进行解析,而不是有编译器在编译时验证和绑定。

在C# 4.0 中,提供了如下4个绑定方法

1.针对一个底层CLR类型使用反射。

2.调用一个自定义IDynamicMetaObjectProvider,它使一个DynamicMetaObject变得可用。

3.通过COM的IUnknow和IDispatch接口来调用。

4.调用由动态语言定义的类型。

             //对Dynamic使用GetType(),会返回基础类型,而不是Dynamic.
            dynamic data = "Hello!  My name is Inigo Montoya";
            Console.WriteLine(data.GetType());
            Console.WriteLine(data);
            //data.length 是动态表达式,将在运行时解析
            //成功将引用类型转换成值类型。
            //所有类型都能成功转换成dynamic对象。存在从任何引用类型到Dynamic的隐式转换。
            //从dynamic到一个替代类型的成功转型需要依赖于基础类型。
            data = (double)data.Length;
            //任何Dynamic成员的调用返回的都是一个dynamic对象。
            //但是下面打印的语句是一个基础类型,因为是对象已经经过编译好了。
            data = data * 3.5 + 28.6;
            Console.WriteLine(data.GetType());
            if (data == 2.4 + 112 + 26.2)
            {
                Console.WriteLine("{0} makes for a long triathlon.", data);
            }
            else
            {
                data.NomExistentMethodCallStillCompiles();
            }
            //System.String
            //Hello!  My name is Inigo Montoya
            //System.Double
            //140.6 makes for a long triathlon.

dynamic 是一个objec类型。
 **实现自定义动态对象:关键是实现System.Dynamic.IDynamicMetaObjectProvider接口。但是,不必从头实现接口,只要从System.Dynamic.DynamicObject派生出自定义的派生类型。你只要从众多的成员中重写不合适的。

    public class DynamicXml : DynamicObject
    {
        private XElement Element { get; set; }


        public DynamicXml(XElement element)
        {
            Element = element;
        }
        public static DynamicXml Parse(string text)
        {
            return new DynamicXml(XElement.Parse(text));
        }
        //动态取值
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            bool success = false;
            result = null;
            //FirstOrDefault():返回序列中的第一个元素,如果不包含任何元素,则返回默认值。
            //Descendants():按文档顺序返回此文档或元素的经过筛选的子代元素集合
            XElement firstDescendant = Element.Descendants(binder.Name).FirstOrDefault();
            if(firstDescendant!=null)
            {
                if(firstDescendant.Descendants().Count()>0)
                {
                    result = new DynamicXml(firstDescendant);
                }
                else 
                {
                    result=firstDescendant.Value;
                }
                success =true;
            }
            return success;
        }
        //动态赋值
        public override bool TrySetMember(SetMemberBinder binder,object value)
        {
            bool success=false;
            XElement firstDescendant=Element.Descendants(binder.Name).FirstOrDefault();
            if (firstDescendant != null)
            {
                if(value.GetType()==typeof(XElement))
                {
                    firstDescendant.ReplaceWith(value);
                }
                else
                {
                  firstDescendant.Value=value.ToString();
                }
                success=true ;
            } 
            return success;
        }   
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值