反射需要一整本书来讨论,这里只介绍了Type类和Assembly类,他们是访问反射所提供的拓展功能的主要入口点。这里介绍了自定义特性,它比其它方面更常用,以及如何在运行期间检索自定义特性信息。
一、自定义特性
内置的特性可以根据特性来影响编译。
自定义特性可以在运行期间获取程序信息,可以影响执行程序的方式。例如自定义特性可以用于支持对自定义许可类进行声明性的代码访问
安全检查,把信息与程序元素关联起来,程序元素由测试工具使用,或者在开发可拓展的架构时允许加载插件和模块。
特性的使用:
编译器发现[FieldName("socialsecurityNumber")]时,会把字符串Attribute追加到这个名称后面,形成一个组合名称FieldNameAttribute
,然后搜索所在的名称空间(包括using的)搜索有指定名称的类。
自定义特性,继承自:Attribute
using System;
namespace WhatsNewAttributes
{
[AttributeUsage( // AttributeUsage是.net定义的特性的内置特性说明,可以叫特性的元特性。
AttributeTargets.Class | AttributeTargets.Method,// 应用到的程序元素[必选],使用时候如果是assembly或module的可以放
置在代码中的任何地方
AllowMultiple = true, // 同一个程序元素上是否可以使用多次[可选]
Inherited = false)] // 是否可以继承,接口/类,如果是属性方法那么重载属性方法中也会影响[可选]
public class LastModifiedAttribute : Attribute
{
private readonly DateTime _dateModified;
private readonly string _changes;
// 有两个必选参数
public LastModifiedAttribute(string dateModified, string changes)
{
_dateModified = DateTime.Parse(dateModified);
_changes = changes;
}
//没有set函数,是因为需要作为构造函数参数传入,不能内部指定。
public DateTime DateModified
{
get { return _dateModified; }
}
public string Changes
{
get { return _changes; }
}
// 这个属性为可选参数
public string Issues { get; set; }
}
[AttributeUsage(AttributeTargets.Assembly)]
public class SupportsWhatsNewAttribute : Attribute
{
}
}
二、实体类中使用特性
using System;
using System.Collections;
using System.Text;
using WhatsNewAttributes; // 引入特性定义类
// 声明该程序集使用全局的SupportsWhatsNewAttribute特性类
[assembly: SupportsWhatsNew]
namespace VectorClass
{
// 使用LastModifiedAttribute特性类
[LastModified("14 Feb 2010", "IEnumerable interface implemented " +
"So Vector can now be treated as a collection")]
[LastModified("10 Feb 2010", "IFormattable interface implemented " +
"So Vector now responds to format specifiers N and VE")]
class Vector : IFormattable, IEnumerable
{
public double x, y, z;
public Vector(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
[LastModified("10 Feb 2010", "Method added in order to provide formatting support")]
public string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
return ToString();
string formatUpper = format.ToUpper();
switch (formatUpper)
{
case "N":
return "|| " + Norm().ToString() + " ||";
case "VE":
return String.Format("( {0:E}, {1:E}, {2:E} )", x, y, z);
case "IJK":
StringBuilder sb = new StringBuilder(x.ToString(), 30);
sb.Append(" i + ");
sb.Append(y.ToString());
sb.Append(" j + ");
sb.Append(z.ToString());
sb.Append(" k");
return sb.ToString();
default:
return ToString();
}
}
public Vector(Vector rhs)
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
}
[LastModified("14 Feb 2010", "Method added in order to provide collection support")]
public IEnumerator GetEnumerator()
{
return new VectorEnumerator(this);
}
public override string ToString()
{
return "( " + x + " , " + y + " , " + z + " )";
}
public double this[uint i]
{
get
{
switch (i)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
throw new IndexOutOfRangeException(
"Attempt to retrieve Vector element" + i);
}
}
set
{
switch (i)
{
case 0:
x = value;
break;
case 1:
y = value;
break;
case 2:
z = value;
break;
default:
throw new IndexOutOfRangeException(
"Attempt to set Vector element" + i);
}
}
}
public static bool operator ==(Vector lhs, Vector rhs)
{
if (System.Math.Abs(lhs.x - rhs.x) < double.Epsilon &&
System.Math.Abs(lhs.y - rhs.y) < double.Epsilon &&
System.Math.Abs(lhs.z - rhs.z) < double.Epsilon)
return true;
else
return false;
}
public static bool operator !=(Vector lhs, Vector rhs)
{
return !(lhs == rhs);
}
public static Vector operator +(Vector lhs, Vector rhs)
{
Vector result = new Vector(lhs);
result.x += rhs.x;
result.y += rhs.y;
result.z += rhs.z;
return result;
}
public static Vector operator *(double lhs, Vector rhs)
{
return new Vector(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
}
public static Vector operator *(Vector lhs, double rhs)
{
return rhs * lhs;
}
public static double operator *(Vector lhs, Vector rhs)
{
return lhs.x * rhs.x + lhs.y + rhs.y + lhs.z * rhs.z;
}
public double Norm()
{
return x * x + y * y + z * z;
}
#region enumerator class
[LastModified("14 Feb 2010", "Class created as part of collection support for Vector")]
private class VectorEnumerator : IEnumerator
{
readonly Vector _theVector; // Vector object that this enumerato refers to
int _location; // which element of _theVector the enumerator is currently referring to
public VectorEnumerator(Vector theVector)
{
_theVector = theVector;
_location = -1;
}
public bool MoveNext()
{
++_location;
return (_location > 2) ? false : true;
}
public object Current
{
get
{
if (_location < 0 || _location > 2)
throw new InvalidOperationException(
"The enumerator is either before the first element or " +
"after the last element of the Vector");
return _theVector[(uint)_location];
}
}
public void Reset()
{
_location = -1;
}
}
#endregion
}
}
三、用反射运行期间获取特性
获取一个对象的类型可以通过:
Type t = typeof(obj);//运算符
Type t = obj.GetType()
Type t = Type.GetType(obj);
Type类被Object类关联,也是是所有类型都有一个实例化的Type类。
反射就是利用了这一个内置到语言中的Type类,来获取某一个类或者变量的实例化信息。
Assembly类在System.Reflection命名空间中定义,它允许访问给定程序集的元数据,它也包含可以加载和执行的程序集的方法。
Assembly类包含非常多的属性和方法。
在使用Assembly类实例做一些工作前,需要把相应的程序集加载到正在允许的进程中,相对目录可以用:AssemblyLoad(someassembly)。
绝对目录可以用Assembly.LoadFrom(@"c:\my\someassembly");
加载了程序集后,可以用Assembly类访问程序集中定义的所有类型,也可以查找自定义特性(取决于实体类中的元素上使用的特性)。
查找全局的特性,可以用GetCustomAttributes(assembly);指定的类型也可以用重载的GetCustomAttributes来获取。
获取的特性都是基类的,如果需要转换为自定义类型的特性,那么需要显式的转换为自定义的类型。
using System;
// 利用了System.Reflection下的Assembly反射类
using System.Reflection;
using System.Text;
using System.Windows.Forms;
// 使用特性类
using WhatsNewAttributes;
using VectorClass;
namespace LookUpWhatsNew
{
internal class WhatsNewChecker
{
private static readonly StringBuilder outputText = new StringBuilder(1000);
private static DateTime backDateTo = new DateTime(2010, 2, 1);
private static void Main()
{
int n = 10;
Type t = n.GetType();
// 1.加载特性实体类
Assembly theAssembly = Assembly.Load("VectorClass");
// 2.返回特性类
Attribute supportsAttribute =
Attribute.GetCustomAttribute(
theAssembly, typeof (SupportsWhatsNewAttribute));
string name = theAssembly.FullName;
AddToMessage("Assembly: " + name);
if (supportsAttribute == null)
{
AddToMessage(
"This assembly does not support WhatsNew attributes");
return;
}
else
{
AddToMessage("Defined Types:");
}
// 3.对应用了特征的实体类进行遍历输出自定义特征信息
Type[] types = theAssembly.GetTypes();
foreach (Type definedType in types)
DisplayTypeInfo(definedType);
MessageBox.Show(outputText.ToString(),
"What\'s New since " + backDateTo.ToLongDateString());
//Console.ReadLine();
}
private static void DisplayTypeInfo(Type type)
{
// make sure we only pick out classes
// 不是类直接返回
if (!(type.IsClass))
return;
AddToMessage("\nclass " + type.Name);
// 1)获取该类型上的所有特性
Attribute[] attribs = Attribute.GetCustomAttributes(type);
if (attribs.Length == 0)
AddToMessage("No changes to this class");
else
foreach (Attribute attrib in attribs)
WriteAttributeInfo(attrib);
// 2)获取该类型上的所有方法,用于获取方法上的所有特性
MethodInfo[] methods = type.GetMethods();
AddToMessage("CHANGES TO METHODS OF THIS CLASS:");
foreach (MethodInfo nextMethod in methods)
{
// 获取一个方法上的所有特性
object[] attribs2 =
nextMethod.GetCustomAttributes(
typeof (LastModifiedAttribute), false);
if (attribs2 != null)
{
AddToMessage(
nextMethod.ReturnType + " " + nextMethod.Name + "()");
foreach (Attribute nextAttrib in attribs2)
WriteAttributeInfo(nextAttrib);
}
}
}
private static void WriteAttributeInfo(Attribute attrib)
{
// 3)强转类型为自定义特征类,调用自定义特征类的属性和方法
LastModifiedAttribute lastModifiedAttrib =
attrib as LastModifiedAttribute;
if (lastModifiedAttrib == null)
return;
// check that date is in range
DateTime modifiedDate = lastModifiedAttrib.DateModified;
if (modifiedDate < backDateTo)
return;
AddToMessage(" MODIFIED: " +
modifiedDate.ToLongDateString() + ":");
AddToMessage(" " + lastModifiedAttrib.Changes);
if (lastModifiedAttrib.Issues != null)
AddToMessage(" Outstanding issues:" +
lastModifiedAttrib.Issues);
}
private static void AddToMessage(string message)
{
outputText.Append("\n" + message);
}
}
}