.NET基础 (17)反射
反射
1 请解释反射的基本原理和其实现的基石
2 .NET提供了哪些类型来实现反射
3 如何实现动态地发射程序集
4 如何利用反射来实现工厂模式
反射
1 请解释反射的基本原理和其实现的基石
反射是一种动态分析程序集、模块、类型、字段等目标对象的机制,它的实现依托于元数据。元数据是存储在PE文件中的数据块,它详细记录了程序集后模块内部的结构、引用类型、程序集和清单。
2 .NET提供了哪些类型来实现反射
在System.Reflection命名空间下,.NET提供了丰富的实现反射机制的类型,可以达到读取元数据中所有信息并且动态创建类型对象的功能。
示例:对程序集进行动态分析
首先创建一个程序集
namespace NET.MST.Sixth.SimpleAssembly
{
/// <summary>
/// 创建一个包含私有成员、特性、方法的简单类型
/// </summary>
[Serializable]
class SimpleAssembly
{
private String _MyString;
public SimpleAssembly(String mystring)
{
_MyString = mystring;
}
public override string ToString()
{
return _MyString;
} static void Main(string[] args)
{
Console.WriteLine("简单程序集");
Console.Read();
}
}
}
对程序集进行分析
partial class UseReflection
{
/// <summary>
/// 对一个程序集进行分析
/// </summary>
/// <param name="assembly"></param>
private static void AnalyzeAssembly(Assembly assembly)
{
Console.WriteLine("程序集名字:" + assembly.FullName);
Console.WriteLine("程序集位置:" + assembly.Location);
Console.WriteLine("程序集是否在GAC中:" +
assembly.GlobalAssemblyCache.ToString());
Console.WriteLine("包含程序集的模块名" +
assembly.ManifestModule.Name);
Console.WriteLine("运行程序集需要的CLR版本:" +
assembly.ImageRuntimeVersion);
Console.WriteLine("现在开始分析程序集中的模块");
Module[] modules = assembly.GetModules();
foreach (Module module in modules)
AnalyzeModule(module);
////递归分析引用程序集
////这里的代码供读者参考
//Console.WriteLine("开始分析引用的程序集");
//AssemblyName[] refassemblies = assembly.GetReferencedAssemblies();
//foreach (AssemblyName refname in refassemblies)
//{
// Assembly refassembly = Assembly.Load(refname);
// AnalyzeAssembly(refassembly);
//}
}
}
partial class UseReflection
{
/// <summary>
/// 对一个模块进行分析
/// </summary>
/// <param name="module">模块</param>
private static void AnalyzeModule(Module module)
{
Console.WriteLine("模块名:" + module.Name);
Console.WriteLine("模块的UUID:" + module.ModuleVersionId);
Console.WriteLine("开始分析模块下的类型");
Type[] types = module.GetTypes();
foreach (Type type in types)
AnalyzeType(type);
}
}
partial class UseReflection
{
/// <summary>
/// 对一个类型进行分析
/// </summary>
/// <param name="type">类型</param>
private static void AnalyzeType(Type type)
{
Console.WriteLine("类型名字:" + type.Name);
Console.WriteLine("类型的类别是:" + type.Attributes);
if (type.BaseType != null)
Console.WriteLine("类型的基类是:" + type.BaseType.Name);
Console.WriteLine("类型的GUID是:" + type.GUID);
//设置感兴趣的类型成员
BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Static | BindingFlags.Instance);
//分析成员
FieldInfo[] fields = type.GetFields(flags);
if (fields.Length > )
{
Console.WriteLine("开始分析类型的成员");
foreach (FieldInfo field in fields)
AnalyzeField(field);
}
//分析包含的方法
MethodInfo[] methods = type.GetMethods(flags);
if (methods.Length > )
{
Console.WriteLine("开始分析类型的方法");
foreach (MethodInfo method in methods)
AnalyzeMethod(method);
}
//分析属性
PropertyInfo[] properties = type.GetProperties(flags);
if (properties.Length > )
{
Console.WriteLine("开始分析类型的属性");
foreach (PropertyInfo property in properties)
AnalyzeProperty(property);
}
}
}
partial class UseReflection
{
/// <summary>
/// 对一个成员进行分析,这里只做简单的分析
/// 可以进一步分析成员的可访问级别,
/// 或通过成员得到包含它的类型、模块等
/// </summary>
/// <param name="field">成员</param>
private static void AnalyzeField(FieldInfo field)
{
Console.WriteLine("成员名字:" + field.Name);
Console.WriteLine("成员的类别:" + field.Attributes);
Console.WriteLine("成员的类型名:" + field.FieldType.Name);
}
/// <summary>
/// 对一个方法进行分析
/// </summary>
/// <param name="method"></param>
private static void AnalyzeMethod(MethodInfo method)
{
Console.WriteLine("方法名字:" + method.Name);
Console.WriteLine("方法的类别:" + method.Attributes);
Console.WriteLine("开始分析方法的参数");
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length <= )
Console.WriteLine("方法没有参数");
foreach (ParameterInfo parameter in parameters)
AnalyzeParameter(parameter);
ParameterInfo retpar = method.ReturnParameter;
Console.WriteLine("分析方法的返回参数");
AnalyzeParameter(retpar);
}
/// <summary>
/// 分析方法参数
/// </summary>
/// <param name="parameter"></param>
private static void AnalyzeParameter(ParameterInfo parameter)
{
Console.WriteLine("参数名字:" + parameter.Name);
Console.WriteLine("参数的类别:" + parameter.Attributes);
Console.WriteLine("参数的类型:" + parameter.ParameterType.Name);
}
/// <summary>
/// 分析属性
/// </summary>
/// <param name="property"></param>
private static void AnalyzeProperty(PropertyInfo property)
{
Console.WriteLine("属性名字:" + property.Name);
Console.WriteLine("属性的类别:" + property.Attributes);
Console.WriteLine("是否可读:" + property.CanRead.ToString());
Console.WriteLine("是否可写:" + property.CanWrite.ToString());
}
}
调用:
/// <summary>
/// 这里的特性要求程序的运行需要完全信任的安全级别
/// </summary>
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
partial class UseReflection
{
static void Main(string[] args)
{
//需要根据代码位置进行更新
//对程序集进行遍历分析
Assembly assembly = Assembly.LoadFrom(@"D:\project\CSHARP\SimpleAssembly.exe");
AnalyzeAssembly(assembly); //创建一个程序集中的类型的对象
//这里尝试创建SimpleAssembly对象
Console.WriteLine("利用反射创建类型");
String[] pars = { "测试反射" };
Object o = assembly.CreateInstance(assembly.GetModules()[].GetTypes()[].ToString(),
true, BindingFlags.CreateInstance, null, pars, null, null);
Console.WriteLine(o);
Console.Read();
}
}
输出:
运行程序集需要的CLR版本:v4.0.30319
现在开始分析程序集中的模块
模块名:SimpleAssembly.exe
模块的UUID:8f75ce48-76e6-40af-9f7f-adbd2fab16c6
开始分析模块下的类型
类型名字:SimpleAssembly
类型的类别是:AutoLayout, AnsiClass, Class, Serializable, BeforeFieldInit
类型的基类是:Object
类型的GUID是:c0a636a7--35f3--4ac9ac7f9fe7
开始分析类型的成员
成员名字:_MyString
成员的类别:Private
成员的类型名:String
开始分析类型的方法
方法名字:ToString
方法的类别:PrivateScope, Public, Virtual, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:String
方法名字:Main
方法的类别:PrivateScope, Private, Static, HideBySig
开始分析方法的参数
参数名字:args
参数的类别:None
参数的类型:String[]
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:Equals
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
参数名字:obj
参数的类别:None
参数的类型:Object
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Boolean
方法名字:GetHashCode
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Int32
方法名字:GetType
方法的类别:PrivateScope, Public, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Type
方法名字:Finalize
方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:MemberwiseClone
方法的类别:PrivateScope, Family, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Object
类型名字:DownloadHelper
类型的类别是:AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
类型的基类是:Object
类型的GUID是:7c376104-a9d8-3a0b-89a2-ae567c8a86d9
开始分析类型的方法
方法名字:DownloadBaiduWenku
方法的类别:PrivateScope, Public, Static, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:ToString
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:String
方法名字:Equals
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
参数名字:obj
参数的类别:None
参数的类型:Object
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Boolean
方法名字:GetHashCode
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Int32
方法名字:GetType
方法的类别:PrivateScope, Public, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Type
方法名字:Finalize
方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:MemberwiseClone
方法的类别:PrivateScope, Family, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Object
类型名字:RARHelper
类型的类别是:AutoLayout, AnsiClass, Class, BeforeFieldInit
类型的基类是:Object
类型的GUID是:d5b4c611-21be-375b-9e4b-f4d9b3a20ad8
开始分析类型的方法
方法名字:Exists
方法的类别:PrivateScope, Public, Static, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Boolean
方法名字:CompressRAR
方法的类别:PrivateScope, Public, HideBySig
开始分析方法的参数
参数名字:path
参数的类别:None
参数的类型:String
参数名字:rarPath
参数的类别:None
参数的类型:String
参数名字:rarName
参数的类别:None
参数的类型:String
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:UnRAR
方法的类别:PrivateScope, Public, HideBySig
开始分析方法的参数
参数名字:path
参数的类别:None
参数的类型:String
参数名字:rarPath
参数的类别:None
参数的类型:String
参数名字:rarName
参数的类别:None
参数的类型:String
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Boolean
方法名字:ToString
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:String
方法名字:Equals
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
参数名字:obj
参数的类别:None
参数的类型:Object
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Boolean
方法名字:GetHashCode
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Int32
方法名字:GetType
方法的类别:PrivateScope, Public, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Type
方法名字:Finalize
方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:MemberwiseClone
方法的类别:PrivateScope, Family, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Object
类型名字:TextHelper
类型的类别是:AutoLayout, AnsiClass, Class, Public, BeforeFieldInit
类型的基类是:Object
类型的GUID是:d80fb451--3d34--c0216b355090
开始分析类型的方法
方法名字:GetFileEncodeType
方法的类别:PrivateScope, Public, Static, HideBySig
开始分析方法的参数
参数名字:filename
参数的类别:None
参数的类型:String
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Encoding
方法名字:ToString
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:String
方法名字:Equals
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
参数名字:obj
参数的类别:None
参数的类型:Object
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Boolean
方法名字:GetHashCode
方法的类别:PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Int32
方法名字:GetType
方法的类别:PrivateScope, Public, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Type
方法名字:Finalize
方法的类别:PrivateScope, Family, Virtual, HideBySig, VtableLayoutMask
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Void
方法名字:MemberwiseClone
方法的类别:PrivateScope, Family, HideBySig
开始分析方法的参数
方法没有参数
分析方法的返回参数
参数名字:
参数的类别:None
参数的类型:Object
利用反射创建类型
测试反射
3 如何实现动态地发射程序集
在System.Relflection.Emit命名空间下,定义一系列用于动态发射中间代码的类型,这些类型可以用来动态地创建程序集的功能。生成的中间代码被直接写入内存中,而不是以代码的形式驻留在硬盘上。
示例:动态地发射MSIL指令构成一个程序集:
class MainClass
{
/// <summary>
/// 使用发射的类型
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//定义构造方法的参数
Object[] ctorParams = new Object[];
ctorParams[] = ;
ctorParams[] = ;
//发射程序集,并得到AddClass类型
Type type = CreateAssembly();
//新建AddClass对象
object ptInstance = Activator.CreateInstance(type, ctorParams);
//调用动态发射的ToString方法
Console.WriteLine(ptInstance.ToString());
//调用动态发射的GetResult方法
MethodInfo info = type.GetMethod("GetResult",new Type[]);
long result = (long)info.Invoke(ptInstance, null);
Console.WriteLine(result.ToString());
Console.Read();
} /// <summary>
/// 用来动态发射一个程序集的中间代码
/// 放回发射的类型
/// 创建的中间代码相当于这样的C#代码:
// public class AddClass
//{
// private long first;
// private long second; // public AddClass(long f, long s)
// {
// first = f;
// second = s;
// }
// public long GetResult()
// {
// return first + second;
// } // public override string ToString()
// {
// return "第一个数字是:" +
// first.ToString() +
// "\r\n第二个数字是:" +
// second.ToString();
// }
// }
/// </summary>
static Type CreateAssembly()
{
//在当前应用程序域中定义新程序集
AppDomain myDomain = Thread.GetDomain();
AssemblyName myAsmName = new AssemblyName();
myAsmName.Name = "NewAssembly";
AssemblyBuilder assemblybuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
//定义模块
ModuleBuilder addclassModule = assemblybuilder.DefineDynamicModule("AddClass", "AddClass.dll");
//定义模块中的类型
TypeBuilder addclass = addclassModule.DefineType("AddClass", TypeAttributes.Public);
//这个类型将包含两个私有成员
//名字分别为:first和second
FieldBuilder first = addclass.DefineField("first", typeof(long), FieldAttributes.Private);
FieldBuilder second = addclass.DefineField("second", typeof(long), FieldAttributes.Private);
//为AddClass定义一个公共构造方法
//接受两个长整型参数
Type[] ctorParams = new Type[] { typeof(long), typeof(long) };
//AddClass的基类是System.Object
Type objType = Type.GetType("System.Object");
//得到无参数构造方法
ConstructorInfo objCtor = objType.GetConstructor(new Type[]);
//AddClass的公共构造方法
ConstructorBuilder addCtor = addclass.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctorParams);
//开始生成构造方法的中间代码
ILGenerator ctorIL = addCtor.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call, objCtor);
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
ctorIL.Emit(OpCodes.Stfld, first);
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_2);
ctorIL.Emit(OpCodes.Stfld, second);
ctorIL.Emit(OpCodes.Ret);
//这里生成long GetResult()方法
//用以得到两个数字相加的结果
MethodBuilder resultMethod = addclass.DefineMethod("GetResult", MethodAttributes.Public, typeof(long), new Type[]);
//发射GetResult方法的中间代码
ILGenerator resultIL = resultMethod.GetILGenerator();
// ILGenerator.EmitWriteLine(string) 生成一个字符串对象,
//并且通过控制台输出
resultIL.EmitWriteLine("开始执行相加:");
//执行相加程序
//这里的IL代码用来导入两个成员变量,相加并返回结果
resultIL.Emit(OpCodes.Ldarg_0);
resultIL.Emit(OpCodes.Ldfld, first);
resultIL.Emit(OpCodes.Ldarg_0);
resultIL.Emit(OpCodes.Ldfld, second);
resultIL.Emit(OpCodes.Add);
resultIL.Emit(OpCodes.Ret);
//发射String ToString方法
MethodBuilder tostringMethod = addclass.DefineMethod("ToString", MethodAttributes.Virtual | MethodAttributes.Public, typeof(String), new Type[]);
ILGenerator stringIL = tostringMethod.GetILGenerator();
stringIL.Emit(OpCodes.Ldstr,"第一个数字是:");
stringIL.Emit(OpCodes.Ldarg_0);
stringIL.Emit(OpCodes.Ldflda, first);
stringIL.Emit(OpCodes.Call, typeof(long).GetMethod("ToString",new Type[]));
stringIL.Emit(OpCodes.Ldstr, "\r\n第二个数字是:");
stringIL.Emit(OpCodes.Ldarg_0);
stringIL.Emit(OpCodes.Ldflda, second);
stringIL.Emit(OpCodes.Call, typeof(long).GetMethod("ToString", new Type[]));
Type[] types = new Type[];
for (int i = ; i < types.Length; i++)
types[i] = typeof(String);
stringIL.Emit(OpCodes.Call, typeof(String).GetMethod("Concat",types));
stringIL.Emit(OpCodes.Ret);
//说明方法重载System.Object方法
addclass.DefineMethodOverride(tostringMethod, typeof(System.Object).GetMethod("ToString"));
return addclass.CreateType();
}
}
输出:
第一个数字是:1000
第二个数字是:2000
开始执行相加:
3000
4 如何利用反射来实现工厂模式
使用反射可以实现灵活性较高的工厂模式 ,其关键在于动态地查找产品所包含的所有零件,而不需要通过代码来逐一分析使用者的需求。反射工厂模式具有灵活性高、运行效率相对较低等特点。
示例:
以打造一个房子为例,可能需要窗户、屋顶、柱子等零部件。有的屋子需要多根柱子,而有的屋子又不需要窗户。这样的需求,采用工厂模式就非常适合。
传统的工厂模式的架构图:
工厂模式传统实现:
/// <summary>
/// 使用者
/// </summary>
class Customer
{
static void Main(string[] args)
{
//根据需要获得不同的产品零件
IProduct window = FactoryManager.GetProduct(RoomParts.Window);
IProduct roof = FactoryManager.GetProduct(RoomParts.Roof);
IProduct pillar = FactoryManager.GetProduct(RoomParts.Pillar);
Console.Read();
}
}
/// <summary>
/// 屋子产品的零件
/// </summary>
enum RoomParts
{
Roof,
Window,
Pillar
}
/// <summary>
/// 工厂接口
/// </summary>
interface IFactory
{
IProduct Produce();
}
/// <summary>
/// 产品接口
/// </summary>
interface IProduct
{
String GetName();
}
/// <summary>
/// 工厂管理者
/// </summary>
class FactoryManager
{
public static IProduct
GetProduct(RoomParts part)
{
IFactory factory = null;
//这里就是传统工厂模式的弊端
//工厂管理者和工厂类族耦合
switch (part)
{
case RoomParts.Pillar:
factory = new PillarFactory();
break;
case RoomParts.Roof:
factory = new RoofFactory();
break;
case RoomParts.Window:
factory = new WindowFactory();
break;
}
IProduct product = factory.Produce();
Console.WriteLine("生产了一个产品:" +
product.GetName());
return product;
}
}
#region 工厂类族
class RoofFactory : IFactory
{
public IProduct Produce()
{
return new Roof();
}
}
class WindowFactory : IFactory
{
public IProduct Produce()
{
return new Window();
}
}
class PillarFactory : IFactory
{
public IProduct Produce()
{
return new Pillar();
}
}
#endregion #region 产品类族
class Roof : IProduct
{
public String GetName()
{
return "屋顶";
}
}
class Window : IProduct
{
public String GetName()
{
return "窗户";
}
}
class Pillar : IProduct
{
public String GetName()
{
return "柱子";
}
}
#endregion
输出:
生产了一个产品:窗户
生产了一个产品:屋顶
生产了一个产品:柱子
反射工厂模式实现:
/// <summary>
/// 使用者
/// </summary>
class Customer
{
static void Main(string[] args)
{
//使用者的代码和传统实现一样
IProduct window = FactoryManager.GetProduct(RoomParts.Window);
IProduct pillar = FactoryManager.GetProduct(RoomParts.Pillar);
IProduct roof = FactoryManager.GetProduct(RoomParts.Roof);
Console.Read();
}
}
/// <summary>
/// 工厂管理类型
/// </summary>
class FactoryManager
{
public static IProduct GetProduct(RoomParts part)
{
Factory factory = new Factory();
IProduct product = factory.Produce(part);
Console.WriteLine("生产了一个产品:" +
product.GetName());
return product;
}
} /// <summary>
/// 屋子产品的零件
/// </summary>
enum RoomParts
{
Roof,
Window,
Pillar
}
/// <summary>
/// 这个特性用来附加在产品类型之上,
/// 来标注该类型代码哪个产品,方便反射使用
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
class ProductAttribute : Attribute
{
//标注零件的成员
private RoomParts _myRoomPart; public ProductAttribute(RoomParts part)
{
_myRoomPart = part;
}
public RoomParts RoomPart
{
get
{
return _myRoomPart;
}
}
}
/// <summary>
/// 这个特性用来附加在产品接口之上
/// 来标注一共实现了多少产品零件,方便反射使用
/// </summary>
[AttributeUsage(AttributeTargets.Interface)]
class ProductListAttribute : Attribute
{
private Type[] _myList; public ProductListAttribute(Type[] Products)
{
_myList = Products;
}
public Type[] ProductList
{
get
{
return _myList;
}
}
} #region 产品类族
/// <summary>
/// 产品零件接口,
/// 需要添加所有实现该接口的列表
/// </summary>
[ProductList(new Type[]{
typeof(Roof),
typeof(Window),
typeof(Pillar)})]
interface IProduct
{
String GetName();
}
/// <summary>
/// 屋顶类型
/// </summary>
[Product(RoomParts.Roof)]
class Roof : IProduct
{
public String GetName()
{
return "屋顶";
}
}
/// <summary>
/// 窗户类型
/// </summary>
[Product(RoomParts.Window)]
class Window : IProduct
{
public String GetName()
{
return "窗户";
}
}
/// <summary>
/// 柱子类型
/// </summary>
[Product(RoomParts.Pillar)]
class Pillar : IProduct
{
public String GetName()
{
return "柱子";
}
}
#endregion #region 工厂类
/// <summary>
/// 工厂类型,这里不再需要一个类族,
/// 而只需要一个工厂类型
/// </summary>
class Factory
{
public IProduct Produce(RoomParts part)
{
//通过反射,从IProduct 接口中获得属性,
//从而获得所有的产品零件列表
ProductListAttribute Attr = (ProductListAttribute)
Attribute.GetCustomAttribute(typeof(IProduct),
typeof(ProductListAttribute)); //遍历所有的实现产品零件类型
foreach (Type type in Attr.ProductList)
{
//利用反射查找其属性
ProductAttribute pa = (ProductAttribute)
Attribute.GetCustomAttribute(
type, typeof(ProductAttribute));
//确定是否是需要的零件
if (pa.RoomPart == part)
{
//再一次利用反射
//创建产品零件类型
Object product = Assembly.GetExecutingAssembly().
CreateInstance(type.FullName);
return product as IProduct;
}
}
//不应该到达这里
return null;
}
}
#endregion
转载请注明出处:
作者:JesseLZJ
出处:http://jesselzj.cnblogs.com
.NET基础 (17)反射的更多相关文章
- GO学习-(17) Go语言基础之反射
Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...
- [.net 面向对象编程基础] (17) 数组与集合
[.net 面向对象编程基础] (17) 数组与集合 学习了前面的C#三大特性,及接口,抽象类这些相对抽象的东西以后,是不是有点很累的感觉.具体的东西总是容易理解,因此我们在介绍前面抽象概念的时候,总 ...
- 黑马程序员:Java基础总结----反射
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
- Go语言基础之反射
Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...
- 十七. Python基础(17)--正则表达式
十七. Python基础(17)--正则表达式 1 ● 正则表达式 定义: Regular expressions are sets of symbols that you can use to cr ...
- Python 基础 三 反射
Python 基础 三 反射 今天我们先介绍一下反射这个概念,啥是反射?反射就是自己检测自己.在我们Python的面向对象中的反射是啥意思呢?就是通过字符串的形式操作对象相关的属性.python中的一 ...
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- JAVA安全基础之反射
JAVA安全基础之反射 在JAVA安全中,反射是一个经常使用的技术,所以熟悉使用反射是非常必要的.下面就简单的讲下JAVA的反射的用法 什么是反射 每个类都有对应的Class类对象,该Class类对象 ...
- 黑马程序员_Java基础:反射机制(Reflection)总结
------- android培训.java培训.期待与您交流! ---------- 反射在java中有非常重大的意义,它是一种动态的相关机制,可以于运行时加载.探知.使用编译期间完全未知的clas ...
- C#基础|初探反射
什么是反射 我们编写的C#代码都可以编译成exe文件或dll文件.暂时先把他们叫做程序集吧,程序集中包含了很多信息.你写了一个类,类中会有字段,有属性,有方法,编译是会把这些信息保存在程序集中,暂时把 ...
随机推荐
- APN与VPDN的主要区别
VPDN APN 安全性 二次认证,加密 一次认证,没有加密 企业成本 高 低 对GGSN要求 可接受动态配置LNS参数信息,对GGSN性能影响小. 静态配置GRE隧道参数,性能影响较大,部分厂家对G ...
- 不同复制模式下,如何忽略某些binlog事件
在MySQL复制中,如果slave节点上遇到错误,比如数据不存在或者主键冲突等错误时,想要忽略这些错误,可以采用以下几种方法: 1.未启用GTID模式时 只需通过设定 SQL_SLAVE_SKIP_C ...
- Java 迭代器 Iterator
迭代器模式 迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式.这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示. 迭代器模式属于行 ...
- Java-Runoob-高级教程-实例-环境设置实例:4.Java 实例 – 如何查看当前 Java 运行的版本?
ylbtech-Java-Runoob-高级教程-实例-环境设置实例:4.Java 实例 – 如何查看当前 Java 运行的版本? 1.返回顶部 1. Java 实例 - 如何查看当前 Java 运行 ...
- Bootstrap-Other:v2 教程
ylbtech-Bootstrap-Other:v2 教程 1.返回顶部 1. Bootstrap v2 教程 Bootstrap,来自 Twitter,是基于 HTML.CSS.JAVASCRIPT ...
- [Java.web]MVC 案例-开发用户模块(注册)
代码下载 生成后的 user.xml 路径在 X:\day09_user\WebRoot\WEB-INF\classes\users.xml 使用测试 在 day09 项目上右键 -> Run ...
- UI“三重天”之appium(一)
官方介绍: Appium is an open-source tool for automating native, mobile web, and hybrid applications on iO ...
- 第2课 GUI程序实例分析
1. GUI程序开发概述 (1)现代操作系统提供原生SDK支持GUI程序开发 (2)GUI程序开发是现代操作系统上的主流技术 (3)不同操作系统上的GUI开发原理相同 (4)不同操作系统上的GUI S ...
- NodeJs通过async/await处理异步
##场景 远古时代 我们在编写express后台,经常要有许多异步IO的处理.在远古时代,我们都是用chunk函数处理,也就是我们最熟悉的那种默认第一个参数是error的函数.我们来模拟一个Mongo ...
- 【CentOS 6.5】【转】新版本linux生成xorg.conf
新版本的linux如何生成xorg.conf 较新版本的linux系统都已经没有xorg.conf文件,但是有时候为了对显示做微调或为了支持多屏显示等原因,还需要手工生成一个xorg.conf,然后根 ...