反射(reflection),按照定义,即为对程序集中的元数据进行检查的过程。而特性,按本人的理解,就是在程序集中插入自定义的元数据标记,为类或类成员(属性,方法,字段等)打上特定的标记,方便查找和调用。在.netFramework框架下,System.Reflection 及提供了充足的反射类型,,(MethodInfo, PropertyInfo, FieldInfo,等)均是在检查元数据过程中非常实用的类。对于反射有个不容忽视的强大特性,那就是在CAS(code-access-security)的前提下,它可以绕过访问等级制度(见以下示例),可以直接调用并对私有成员进行赋值,当然对于代码安全而言也是个不容忽视的漏洞隐患。 另外也因为有了反射和特性,因此出现了新型的编程模型,相对于OOP(面向对象),出现了AOP(面向方面编程,Aspect-oriented programing)足可见其强大。
以下为测试反射和特性的小例子,按照特性来查找类成员,并调用和赋值的例子,其中包括对私有属性和私有方法的访问。
访问私有成员时需要注意BindingFlags.NonPublic 以及为实例还是静态成员的BindingFlags.Instance;
文件1:
using System.IO;
using System;
using TestAttributes;
using System.Reflection;
class Program
{
static void Main()
{
var type=typeof(TestClassA);
//invoke the methods in TestClassA with ExportAttribute;
ExportAttribute.InvokeMethod("TestMethod1",type,null);
var parameters=new string[]{"anyname"};
ExportAttribute.InvokeMethod("Print",type,parameters);
//set the private property in TestClassA with value;
var class1=new TestClassA();
SetPropertyValue(class1,"level","LevelClass1");
class1.Print("anynameclass1");
}
//Set property Value;
public static bool SetPropertyValue(object target,string propertyName,object propertyValue)
{
var type=target.GetType();
var property=type.GetProperty(propertyName,BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Public);
if(property!=null)
{
var attributes=property.GetCustomAttributes(false);
foreach(var attribute in attributes)
{
if(attribute is ExportAttribute)
{
property.SetValue(target,propertyValue,null);
return true;
}
}
}
return false;
}
}
文件2:
using System.Reflection;
using System;
using System.IO;
namespace TestAttributes
{
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Property)]
public class ExportAttribute: Attribute
{
public string catalogs {get;set;}
//the classtype must have a default constructor; if the parameter of the method is null ,then the parameters must be null;
public static bool InvokeMethod(string MethodName,Type classtype,object[] parameters)
{
if(MethodName==null||classtype==null)
return false;
var flag=false;
var methodInfos=classtype.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
foreach(var info in methodInfos)
{
if(info.Name==MethodName&&IsHaveExportAttribute(info))
{
flag=true;
var instance=Activator.CreateInstance(classtype);
info.Invoke(instance,parameters);
}
}
return flag;
}
public static bool IsHaveExportAttribute(MethodInfo info)
{
if(info==null)
{
return false;
}
var attributes=info.GetCustomAttributes(false);
foreach (var attribute in attributes)
{
if(attribute is ExportAttribute)
{
return true;
}
}
return false;
}
}
public class TestClassA
{
private string name {get;set;}
[Export]
private string level {get;set;}
public TestClassA()
{
name="DefaultName";
level="DefaultLevel";
}
[Export]
private void TestMethod1()
{
using (StreamReader reader = new StreamReader("input.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
Console.ReadKey();
}
[Export]
public void Print(string name)
{
Console.WriteLine(name);
Console.WriteLine(level);
Console.ReadKey();
}
}
}
输出:
Testing Reflection
**********************
anyname
DefaultLevel
anynameclass1
LevelClass1