**反射:是在在一个程序集中的元数据进行检查的过程。除此之外,可以利用反射枚举程序集中的所有类型,并搜索满足特定条件的那些类型。通过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;
}
}