反射
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)反射的更多相关文章

  1. GO学习-(17) Go语言基础之反射

    Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...

  2. [.net 面向对象编程基础] (17) 数组与集合

    [.net 面向对象编程基础] (17) 数组与集合 学习了前面的C#三大特性,及接口,抽象类这些相对抽象的东西以后,是不是有点很累的感觉.具体的东西总是容易理解,因此我们在介绍前面抽象概念的时候,总 ...

  3. 黑马程序员:Java基础总结----反射

    黑马程序员:Java基础总结 反射   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...

  4. Go语言基础之反射

    Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...

  5. 十七. Python基础(17)--正则表达式

    十七. Python基础(17)--正则表达式 1 ● 正则表达式 定义: Regular expressions are sets of symbols that you can use to cr ...

  6. Python 基础 三 反射

    Python 基础 三 反射 今天我们先介绍一下反射这个概念,啥是反射?反射就是自己检测自己.在我们Python的面向对象中的反射是啥意思呢?就是通过字符串的形式操作对象相关的属性.python中的一 ...

  7. JAVA基础知识|反射

    一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...

  8. JAVA安全基础之反射

    JAVA安全基础之反射 在JAVA安全中,反射是一个经常使用的技术,所以熟悉使用反射是非常必要的.下面就简单的讲下JAVA的反射的用法 什么是反射 每个类都有对应的Class类对象,该Class类对象 ...

  9. 黑马程序员_Java基础:反射机制(Reflection)总结

    ------- android培训.java培训.期待与您交流! ---------- 反射在java中有非常重大的意义,它是一种动态的相关机制,可以于运行时加载.探知.使用编译期间完全未知的clas ...

  10. C#基础|初探反射

    什么是反射 我们编写的C#代码都可以编译成exe文件或dll文件.暂时先把他们叫做程序集吧,程序集中包含了很多信息.你写了一个类,类中会有字段,有属性,有方法,编译是会把这些信息保存在程序集中,暂时把 ...

随机推荐

  1. 模仿VIMD的模式的简化代码示例

    按numpad0来切换模式,按t显示不同的结果: Numpad0:: tfmode:=!tfmode aaa:=(tfmode=?"AAAA":"BBBB") ...

  2. (转)html中使用表单和input file上传图片

    本文转载自:http://hi.baidu.com/love_1210/item/120e452b42b2a854c38d59eb 客户端代码: <form name="form1&q ...

  3. jemalloc内存分配器详解

    前言 C 中动态内存分配malloc 函数的背后实现有诸派:dlmalloc 之于 bionic:ptmalloc 之于 glibc:allocation zones 之于 mac os x/ios: ...

  4. Django中的Model、Form和ModelForm

    一  Model(数据库操作) 1 数据表操作 两种类型: Code First:创建类→自动生成表 DB First:创建表→自动生成类 (很少用) 单表操作: 一对多:(Forienkey) 多对 ...

  5. django-上下文渲染器,将后端内容提供给模板使用,自定义渲染器

    使用场景:当同一个类容需要出现在多个模板中, 上下文管理器就是将这个内容以字典的形式返回给所有模板,模板通过 {{ key }}取值. 结构:上下文管理器 文件名一般为context_processo ...

  6. call apply 使用

    1.call 跟 apply的主要区别: call传入参数是一个一个传入,而 apply 使用的是数组传入 call(obj,arg1,arg2,arg3,arg4) apply(obj,[arg1, ...

  7. 【转】TCP、UDP数据包大小的限制

    来自:https://blog.csdn.net/caoshangpa/article/details/51530685 1.概述 首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层 ...

  8. 在 springboot 中如何整合 shiro 应用 ?

     Shiro是Apache下的一个开源项目,我们称之为Apache Shiro. 它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与spring Security 一样都是 ...

  9. helm 安装 spinnaker

    $ curl -Lo values.yaml https://raw.githubusercontent.com/kubernetes/charts/master/stable/spinnaker/v ...

  10. fabric本地一键部署LAMP

    一.添加普通用户jeff执行sudo时无需输入密码 $ sudo vim /etc/sudoers ---------------------------------------> ## All ...