您的位置:首页 > 编程语言 > C#

C#中关于反射机制的演示代码

2010-07-06 17:22 330 查看
反射(Reflection)是.NET中的重要机制,通过反射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

先看一个简单例子:

using System;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace Wrox.ProCSharp.TypeView
{
class MainClass
{
static void Main()
{
// modify this line to retrieve details of any
// other data type
Type t = typeof(double);

AnalyzeType(t);
MessageBox.Show(OutputText.ToString(), "Analysis of type " + t.Name);
Console.ReadLine();
}

static void AnalyzeType(Type t)
{
AddToOutput("Type Name:  " + t.Name);
AddToOutput("Full Name:  " + t.FullName);
AddToOutput("Namespace:  " + t.Namespace);
Type tBase = t.BaseType;
if (tBase != null)
AddToOutput("Base Type:" + tBase.Name);
Type tUnderlyingSystem = t.UnderlyingSystemType;
if (tUnderlyingSystem != null)
AddToOutput("UnderlyingSystem Type:" + tUnderlyingSystem.Name);

AddToOutput("/nPUBLIC MEMBERS:");
MemberInfo [] Members = t.GetMembers();
foreach (MemberInfo NextMember in Members)
{
AddToOutput(NextMember.DeclaringType + " " + NextMember.MemberType +
" " + NextMember.Name);
}
}

static void AddToOutput(string Text)
{
OutputText.Append("/n" + Text);
}

static StringBuilder OutputText = new StringBuilder(500);
}
}


再看复杂一点的,定制特性示例,代码如下:

WhatsNewAttributes.cs

using System;

namespace Wrox.ProCSharp.WhatsNewAttributes
{
[AttributeUsage(
AttributeTargets.Class | AttributeTargets.Method,
AllowMultiple = true, Inherited = false)]
public class LastModifiedAttribute : Attribute
{
private DateTime dateModified;
private string changes;
private string issues;

public LastModifiedAttribute(string dateModified, string changes)
{
this.dateModified = DateTime.Parse(dateModified);
this.changes = changes;
}

public DateTime DateModified
{
get
{
return dateModified;
}
}

public string Changes
{
get
{
return changes;
}
}

public string Issues
{
get
{
return issues;
}
set
{
issues = value;
}
}
}

[AttributeUsage(AttributeTargets.Assembly)]
public class SupportsWhatsNewAttribute : Attribute
{
}
}


VectorClass.cs

using System;
using Wrox.ProCSharp.WhatsNewAttributes;
using System.Collections;
using System.Text;

[assembly: SupportsWhatsNew]

namespace Wrox.ProCSharp.VectorClass
{
[LastModified("14 Feb 2002", "IEnumerable interface implemented " +
"So Vector can now be treated as a collection")]
[LastModified("10 Feb 2002", "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 2002", "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 2002", "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 2002", "Class created as part of collection support for Vector")]
private class VectorEnumerator : IEnumerator
{
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)
{
this.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
}
}


LookUpWhatsNew.cs

using System;
using System.Reflection;
using System.Windows.Forms;
using System.Text;
using Wrox.ProCSharp.VectorClass;
using Wrox.ProCSharp.WhatsNewAttributes;

namespace Wrox.ProCSharp.LookUpWhatsNew
{
class WhatsNewChecker
{
static StringBuilder outputText = new StringBuilder(1000);
static DateTime backDateTo = new DateTime(2002, 2, 1);

static void Main()
{
Assembly theAssembly = Assembly.Load("VectorClass");
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:");

Type[] types = theAssembly.GetTypes();
foreach (Type definedType in types)
DisplayTypeInfo(theAssembly, definedType);

MessageBox.Show(outputText.ToString(),
"What/'s New since " + backDateTo.ToLongDateString());
Console.ReadLine();
}

static void DisplayTypeInfo(Assembly theAssembly, Type type)
{
// make sure we only pick out classes
if (!(type.IsClass))
return;
AddToMessage("/nclass " + type.Name);

Attribute[] attribs = Attribute.GetCustomAttributes(type);
if (attribs.Length == 0)
AddToMessage("No changes to this class");
else
foreach (Attribute attrib in attribs)
WriteAttributeInfo(attrib);

MethodInfo[] methods = type.GetMethods();
AddToMessage("CHANGES TO METHODS OF THIS CLASS:");
foreach (MethodInfo nextMethod in methods)
{
object[] attribs2 =
nextMethod.GetCustomAttributes(
typeof(LastModifiedAttribute), false);
if (attribs != null)
{
AddToMessage(
nextMethod.ReturnType + " " + nextMethod.Name + "()");
foreach (Attribute nextAttrib in attribs2)
WriteAttributeInfo(nextAttrib);
}
}
}

static void WriteAttributeInfo(Attribute attrib)
{

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);
}

static void AddToMessage(string message)
{
outputText.Append("/n" + message);
}
}
}


NET可执行应用程序结构
程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。
应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。
反射也可用于创建称为类型浏览器的应用程序,使用户能够选择类型,然后查看有关选定类型的信息。
此外,Jscript等语言编译器使用反射来构造符号表。System.Runtime.Serialization命名空间中的类使用反射来访问数据并确定要永久保存的字段,System.Runtime.Remoting命名空间中的类通过序列化来间接地使用反射。

资料:

/article/4709700.html

http://blog.csdn.net/jamex/archive/2009/03/25/4024043.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: