详解C#编程中的反射机制与方法
Reflection~中文译译反射。译是翻.Net中译取行译译型信息的方式~运.Net的译用程序由部分,几个‘程序集(Assembly)’、‘模译(Module)’、‘译型(class)’译成~而反射提供一译译程的方式~译程序译可以在程序行运期译得译译成部分的相译信息~例如,几个Assembly译可以译得正在行的配件信息~也可以译译的加译配运装装件~以及在配件中译译型信息~译建译译型的译例。装找并Type译可以译得译象的译型信息~此信息包含译象的所
有要素,方法、造器、性等等~通译构属Type译可以得到译些要素的信息~且译用之。并MethodInfo包含方法的信息~通译译译可以得到方法的名、、返回译等~且可以译用之。译如此译~译有个称参数并
FieldInfo、EventInfo等等~译些译都包含在System.Reflection命名空译下。
一、Type译于译取译型信息
System.Type 译译于反射起着核心的作用。反射译求加译的译型译~公共译言行译译译建一译当运将它个 Type。可以使用您 Type 译象的方法、字段、性和嵌套译译译有译译译型的所有信息。属来找
大家行一下下面的代译根据译果分析一下就能比译楚的理解运清Type了
译取译型信息
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MyClass m = new MyClass();
Type type = m.GetType();
Console.WriteLine("译型名:" + type.Name);
Console.WriteLine("译全名,"+type.FullName);
Console.WriteLine("命名空译名:"+type.Namespace);Console.WriteLine("程序集名,"+type.Assembly);
Console.WriteLine("模译名:"+type.Module);
Console.WriteLine("基译名,"+type.BaseType);
Console.WriteLine("是否译,"+type.IsClass);
Console.WriteLine("译的公共成译,");
MemberInfo[] memberInfos = type.GetMembers();//得到所有公共成译foreach (var item in memberInfos)
{
Console.WriteLine("{0}:{1}",item.MemberType,item);}
}
}
class MyClass
{
public string m;
public void test()
{ }
public int MyProperty { get; set; }
}
}
二、译取程序集元据数
Assembly译定译了一程序集~是一可重用、无版本突且可自我描述的公共译言行译译用个它个冲并运
程序造译。因译程序集中是使用元据译行自我描述的~所以我译就能通译其元据得到程序集部的构数数内构
成。译合Assembly和反射能译译取程序集的元据~但是首先要程序集入存中。可以使用数将装内
Assembly译的多译译静Load方法加译程序集。
下面的程序译示程序集的信息
public static void Main()
{
//译取前译行代译的程序集当
Assembly assem = Assembly.GetExecutingAssembly();
Console.WriteLine("程序集全名:"+assem.FullName);Console.WriteLine("程序集的版本,"+assem.GetName().Version);
Console.WriteLine("程序集初始位置:"+assem.CodeBase);
Console.WriteLine("程序集位置,"+assem.Location);Console.WriteLine("程序集入口,"+assem.EntryPoint);
Type[] types = assem.GetTypes();Console.WriteLine("程序集下包含的译型:");
foreach (var item in types){
Console.WriteLine("译,"+item.Name);
}
}
三、译译加译译型
早译定是在译译译译定译象译型~而译译定是在行译才译定译象的译型。利用反射可以译译译译定~译译加译译型~运即
并译用他译的方法~下译是MSDN中的一例子~译译的解译信息译注译个
译译加译译型
namespace ConsoleApplication2{
public class Example
{
private int factor;
public Example(int f)
{
factor = f;
}
public int SampleMethod(int x){
Console.WriteLine("\nExample.SampleMethod({0}) executes.", x);
return x * factor;
}
public static void Main()
{
//译取前译行代译的程序集当
Assembly assem = Assembly.GetExecutingAssembly();
Console.WriteLine("Assembly Full Name:");Console.WriteLine(assem.FullName);
// The AssemblyName type can be used to parse the full name.
AssemblyName assemName = assem.GetName();
Console.WriteLine("\nName: {0}", assemName.Name);Console.WriteLine("Version: {0}.{1}",
assemName.Version.Major, assemName.Version.Minor);Console.WriteLine("\nAssembly CodeBase:");Console.WriteLine(assem.CodeBase);
// 从众个程序集译建一Example译例且用并object译型的引用o指向~同译译用一译入的造函它个参数构
数
Object o = assem.CreateInstance("ConsoleApplication2.Example", false,
BindingFlags.ExactBinding,
null, new Object[] { 2 }, null, null);
//构造Example译的一译译定的方法个SampleMethod
MethodInfo m = assem.GetType("ConsoleApplication2.Example").GetMethod("SampleMethod");
//译用译才译例化好的Example译象o中的SampleMethod方法~译入的译参数42
Object ret = m.Invoke(o, new Object[] { 42 });Console.WriteLine("SampleMethod returned {0}.", ret);
Console.WriteLine("\nAssembly entry point:");Console.WriteLine(assem.EntryPoint);}
}
反射特性,
[Table(Name="dbo.[User]")]
public partial class User
{
当C#译译器译译译性有一特性个属个Table译~首先把字符串会Attribute添加到译名的后面~形成一个称个称译合名TableAttribute~然后在其搜索路的所有命名空译中搜索有相同译名的译。但要注意~如果译特径
性名译尾是Attribute~译译器就不把译字符串加到译合名中。所有的特性都是会称从System.Attribute译型上面派生的。
接着我译看一下来Table特性的定制格式
[AttributeUsageAttribute(AttributeTargets.Class,Inheri
ted=true,AllowMultiple=false)]
public class TalbeAttribute:Attribute
{
在定译译型译使用System.AttributeUsage特性
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
明译自定译特性的使用范译~译里使用了来个Class译式~表示TableAttribute特性只能用在其的它Class译型前面~若放置在Interface或Struct译型前面~或者放在译象成译的前面译出译译译译译。译里译是用译句会 AllowMultiple=false 译句表明译于一译型~译特性只能用一次来个~若一个Class译型前面出译多个TableAttribute~译出译译译译译。若译置会AllowMultiple=true~译译特性可以多次定译~也就是一个Class译型前面可以出译多相同译型的特性。不译译里我译假译一译象只能映射到一个个个数
据表上~有多重映射~因此就指明译同一译型译特性不能多次使用。没个Inherited参数译定译true~就表示译用到译或接口上的特性也可以自译译用到所派生的译或接口上。
我译再看一下定制TalbeAttribute特性的完整例子,
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class TableAttribute : Attribute{
//保存表名的字段
private string _tableName;
public TableAttribute(){
}
public TableAttribute(string tableName)
{
this._tableName = tableName;}
///
/// 映射的表名(表的全名:模式名.表名)
///
public string TableName{
set
{
this._tableName = value;}
get
{
return this._tableName;}
}
}
特性也是一个Class译型~可以有多造函~就像个构数C#的new译句一译~我译向译型附加特性译可以
使用不同的初始化指明使用特性的那造函。我译附加特性译译可以使用参数来个构数“属性名=属性译”的方
法直接指明特性的性译。译特性中定译了一来属个TableName属属数性~译性就是被修译的译象所映射的据译表的名。称
下面我译译一使用特性译行个来O/RMapping的例子~也就是译象译化成将Sql译句
用译译,
User译
[Table("User")]
public class User
{
[Colum("userID", DbType = DbType.Int32)]
public int UserID { get; set; }
[Colum("UserName", DbType = DbType.String)]
public string UserName { get; set; }
}
表特性
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class TableAttribute : Attribute{
//保存表名的字段
private string _tableName;
public TableAttribute()
{
}
public TableAttribute(string tableName){
this._tableName = tableName;
}
///
/// 映射的表名(表的全名:模式名.表名)
///
public string TableName{
set
{
this._tableName = value;}
get
{
return this._tableName;}
}
}
列特性,
[AttributeUsageAttribute(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class ColumAttribute : Attribute
{
private string _columName;
private DbType _dbType ;public ColumAttribute(){
}
public ColumAttribute(string columName)
: this()
{
this._columName = columName;}
public ColumAttribute(string columName, DbType dbType)
: this(columName)
{
this._dbType = dbType;}
//列名
public virtual string ColumName
{
set
{
this._columName = value;}
get
{
return this._columName;}
}
//描述一些特殊的据译译型数
public DbType DbType{
get { return _dbType; }set { _dbType = value; }}
}
ORMHelp
public class ORMHelp
{
public void Insert(object table)
{
Type type = table.GetType();
//定译一字典存放表中字段和译的译译序列个来
Dictionary columValue = new Dictionary();StringBuilder SqlStr=new StringBuilder();SqlStr.Append("insert into ");
//得到表名子
TableAttribute temp = (TalbeAttribute)type.GetCustomAttributes(typeof(TalbeAttribute), false).First();
SqlStr.Append(temp.TableName);
SqlStr.Append("(");
PropertyInfo[] Propertys=type.GetProperties();foreach (var item in Propertys)
{
object[] attributes = item.GetCustomAttributes(false);
foreach (var item1 in attributes)
{
//译得相译性的译属
string value= table.GetType().InvokeMember(item.Name, System.Reflection.BindingFlags.GetProperty,
null, table, null).ToString();
ColumAttribute colum = item1 as ColumAttribute;if (colum != null)
{
columValue.Add(colum.ColumName,value);}
}
}
//拼插入操作字符串
foreach (var item in columValue){
SqlStr.Append(item.Key);
SqlStr.Append(",");
}
SqlStr.Remove(SqlStr.Length-1, 1);SqlStr.Append(") values('");foreach (var item in columValue){
SqlStr.Append(item.Value);
SqlStr.Append("','");
}
SqlStr.Remove(SqlStr.Length - 2, 2);SqlStr.Append(")");
Console.WriteLine(SqlStr.ToString());}
}
SqlStr中的容译内insert into User(userID,UserName) values('1','lfm')
前端使用代译,
前端代译
static void Main(string[] args)
{
ORMHelp o = new ORMHelp();
User u = new User() { UserID=1,UserName="lfm"};
o.Insert(u);
}
译用
例子译译西其译挺译弄得个,弄译译的个,译然能译明译译但却容易译人译得译用价译没,弄有译用价译却又往往译个扯很扯很多译的技译甚至译多译译译译,看起译译译。在译里我量追求译译有译用价译又不译译的例子。来很很懂尽几个
1、使用反射通译译取配置文件译译的译建相译译的译象来
我译先看看来Main函和需要译译加译的译象在同一程序集的情数个况
译译,构
接口
interface ILog
{
bool Write(string message);
bool Write(Exception ex);
}
TextFileLog
class TextFileLog : ILog
{
public bool Write(string message){
string fileDir = ConfigurationManager.AppSettings["LogTarget"].ToString();
using (StreamWriter w = File.AppendText(fileDir)){
// w.Write(" Log Entry : ");
w.WriteLine("译生译译{0}", DateTime.Now.ToLocalTime().ToString());w.WriteLine("日志容译内:{0}", message);
w.WriteLine("-------------------------------");// Update the underlying file.
w.Flush();
w.Close();
}
return true;
}
public bool Write(Exception ex)
{
Write(ex.Message);
return true;
}
}
XmlFileLog
class XmlFileLog : ILog
{
public bool Write(string message)
{
string xmlFilePath = ConfigurationManager.AppSettings["LogTarget"].ToString();
if (File.Exists(xmlFilePath))
{
XmlDocument doc = new XmlDocument();doc.Load(xmlFilePath);
XmlDocumentFragment docFrag = doc.CreateDocumentFragment();
XmlNode nod = doc.SelectSingleNode("Logs");docFrag.InnerXml = "" + DateTime.Now.ToLocalTime().ToString()
+ "" + message + "";
nod.AppendChild(docFrag);
doc.Save(xmlFilePath);
return true;
}
else
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true; //译置译译
settings.ConformanceLevel = ConformanceLevel.Auto;settings.IndentChars = " ";
settings.OmitXmlDeclaration = false;using (XmlWriter writer = XmlWriter.Create(xmlFilePath, settings))
{
//Start writing the XML document
writer.WriteStartDocument(false);
//Start with the root element
writer.WriteStartElement("Logs");
writer.WriteStartElement("Log");
writer.WriteStartElement("Time");
writer.WriteString(DateTime.Now.ToLocalTime().ToString());
writer.WriteEndElement();
writer.WriteStartElement("Message");writer.WriteString(message);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
//Flush the object and write the XML data to the file
writer.Flush();
return true;
}
}
}
public bool Write(Exception ex){
Write(ex.Message);
return true;
}
}
App.config配置
主程序
public static void Main()
{
#region 同程序集下
System.Type
type=System.Type.GetType(ConfigurationManager.AppSetti
ngs["LogType"].ToString());
ILog log = (ILog)Activator.CreateInstance(type);
log.Write(new Exception("异常译译"));
#endregion
}
如果在不同的程序集下~那主函和配置略有不同数会
不同程序集主函数
public static void Main()
{
#region 不同程序集
string assemblyPath =
Path.Combine(Environment.CurrentDirectory,
"LogClassLibrary.dll");
Assembly a = Assembly.LoadFrom(assemblyPath);
Type type =
a.GetType(ConfigurationManager.AppSettings["LogType"].
ToString());
LogClassLibrary.ILog log =
(LogClassLibrary.ILog)type.InvokeMember(null,
BindingFlags.CreateInstance,null,null,null);
log.Write(new Exception("异常译译"));
#endregion
}
译部分源译下译
源译下译
2、件译程技译插
插运从件是指遵循一定的接口译范、可以译译加译和行的程序模译。上面的例子可以看出~通译反射可
以非常方便的译译加译程序集。因此~利用反射的译译加译代译能力~可以容易的译译件。件译程的要点很插插
是使用接口定译件的功能特征。件的宿主程序通译接口译、译和译行件的功能~译译件功能来插插来确装插插
的所有译都必译译译定译件的接口。插
译里只是译译一部分代译~译译分析译看源译
译译构
接口部分
接口
public interface IHost{
List Plugins { get; }int LoadPlugins(string path);ILog GetLog(string name);
}
public interface ILog{
bool Write(string message);bool Write(Exception ex);
}
宿主实译
public class Host : IHost
{
private List plugins = new List();
#region IHost 成译
public List Plugins
{
get { return plugins; }
}
public int LoadPlugins(string path)
{
string[] assemblyFiles = Directory.GetFiles(path, "*.dll");
foreach (var file in assemblyFiles)
{
Assembly assembly = Assembly.LoadFrom(file);foreach (var type in assembly.GetExportedTypes()){
if (type.IsClass && typeof(ILog).IsAssignableFrom(type))
{
ILog plugin = Activator.CreateInstance(type) as ILog;plugins.Add(plugin);
}
}
}
return plugins.Count;
}
public ILog GetLog(string name){
foreach (var item in plugins){
if (item.GetType().ToString()==name){
return item;
}
}
return null;
}
#endregion
}
ILog的译译和上例基本一译~译考参
主程序代译static void Main(string[] args){
Host.Host host = new Host.Host();host.LoadPlugins(".");
InterfaceLayer.ILog log = host.GetLog(ConfigurationManager.AppSettings["LogType"].ToString());
log.Write(new Exception("异常译译"));
}
插件译程源译下译
源译下译
3、分析译象~得到译象中的性译属
大家使用译都用译asp.net中的DropdownList~在译定其译的译候译大多情下我译做的都是同译的事情数况~
译得据源~根据据源中的某些列译定控件~下译我译译译通用情的译理方式。我译只需要提供据集数数来况数
合~以及需要译定到控件的性;两个属text~value,名可。即
public class DDlControl
{
private ListControl underlyingList;
public DDlControl(ListControl underlyingList){
this.underlyingList = underlyingList;
}
public void Add(IDDL ddl)
{
underlyingList.Items.Add(new ListItem(ddl.Name, ddl.Value));}
public void Add(T t, string nameStr, string valueStr){
string name = Convert.ToString(t.GetType().InvokeMember(nameStr, System.Reflection.BindingFlags.GetProperty, null, t, null));
string value = Convert.ToString(t.GetType().InvokeMember(valueStr, System.Reflection.BindingFlags.GetProperty, null, t, null));
Add(new DDLStruct(name,value));
}
public void Clear()
{
underlyingList.Items.Clear();
}
public IDDL SelectedItem
{
get
{
ListItem item = underlyingList.SelectedItem;
return new DDLStruct(item.Text, item.Value);
}
}
public void BindTo(IEnumerable list, string nameStr, string valueStr)
{
Clear();
foreach (var item in list)
{
Add(item, nameStr, valueStr);}
}
public string SelectValue
{
get
{
return underlyingList.SelectedValue;}
set
{
underlyingList.SelectedValue=value;}
}
}
public struct DDLStruct {
public DDLStruct(string name, string value)
{
this.name = name;this.value = value;}
private string name;private string value;public string Name{
get { return name; }}
public string Value{
get { return value; }}
}