我看反射
1.什么是程序集
程序及其类型的数据都被称为元数据,保存在程序的程序集中。
2.在运行过程中检查和处理程序集中元素的功能。
3.Type类是发射的核心,也是进行发射的入口,当你获得了关于类型的Type对象后,就可以根据Type提供的属性和方法获取这个类型的一切信息。
4.获取一个类的类型
(1)使用Type类提供的静态方法GetType()
Type t = Type.GetType("System.IO.Stream");
(2)使用 typeof 操作符
Type t = typeof(System.IO.Stream);
(3)通过类型实例获得Type对象
String name = "Jimmy Zhang";
Type t = name.GetType();
(2)Type 提供了下面的属性,用于获取类型的基本信息,详情见图.
(3)如何进行程序集的加载
我们可以使用 Assembly类型提供的静态方法LoadFrom() 和 Load()
Assembly asm = Assembly.LoadFrom(@"d:\插件2Chinese.dll");
★★当使用LoadFrom()方法的时候,提供的是程序集的文件名,当将一个程序集添加到项目引用中以后,可以直接写“文件名.dll”。
Assembly asm2 = Assembly.Load("插件2Chinese"); //只用提供程序集名称即可,不能提供程序集的后缀名
第一步:应该是获取指定位置的程序集。
根据程序集创建程序集的类型。
把程序集的类型转换成为对象。
接口指向类对象
接口调用方法。
5.如何实现接口并利用接口调用方法
(1)本程序中引用的所有程序集
Assembly[] assm = AppDomain.CurrentDomain.GetAssemblies(); //程序域的当前应用程序域的程序集
foreach (Assembly assm1 in assm)
{
Console.WriteLine(assm1.Location); //当前程序集的路径
}
(2)如何使用接口来进行反射
①创建一个接口的类库
public interface Icomputer //定义为public是为了方便外界进行访问.
{
void Say();
}
②创建一个实现接口的类库,★添加接口类库的引用★,类库中的类要实现这个接口
public class Person:Icomputer
{
#region Icomputer 成员
public void Say()
{
Console.WriteLine("您好啊");
}
#endregion
}
③主程序中添加对接口类库的引用
④加载实现这个接口的类的文件
string s = @"C:\Documents and Settings\Administrator\桌面\复习\发射\插件\bin\Debug\插件.dll"; //实现这个接口的类库所在的位置
Assembly assm = Assembly.LoadFile(s); //程序集中进行加载实现接口的类库
⑤获取程序集中当前实现接口的类库公共类型
Type[] type1 = assm.GetExportedTypes();
★★★由于实现接口的类库中有很多的类,所以要指定是哪一个类的类型。
Type types = type1[0];
⑥把当前类的类型转换成对象
object obj = Activator.CreateInstance(types);
⑦上述目的都是为了实现接口指向类的对象
Icomputer icom = obj as Icomputer;
⑧最终用接口进行方法的调用
icom.Say();
(3)对文件夹下所有的接口进行遍历
string[] files = Directory.GetFiles(@"c:\dll", "*.dll");
foreach (string file in files)
{
Assembly asm = Assembly.LoadFile(file);
Type[] types = asm.GetExportedTypes();
Type type = types[1]; //这个是哪个类文件的索引
//获取类中定义的公共属性
//对类中的所有属性进行遍历
//PropertyInfo[] pro = type.GetProperties();
//foreach (PropertyInfo pro1 in pro)
//{
// Console.WriteLine(pro1);
//}
//访问指定的属性
PropertyInfo[] pro = type.GetProperties();
PropertyInfo pro1 = pro[0];
Console.WriteLine(pro1);
object obj = Activator.CreateInstance(type);//抽象类无法new
Icomputer icom = obj as Icomputer;
icom.Say();
}
(4)获得类的类型
Type type1=typeof(Person); //获取指定类的类型
Type type2=p1.GetType(); //获取p1这个对象指向的的类型
(5)如何获得类中的所有属性
type.GetProperties()
//对类中的所有属性进行遍历
//PropertyInfo[] pro = type.GetProperties();
//foreach (PropertyInfo pro1 in pro)
//{
// Console.WriteLine(pro1);
//}
//访问指定的属性
PropertyInfo[] pro = type.GetProperties();
PropertyInfo pro1 = pro[0];
Console.WriteLine(pro1);
(6)Activator.CreateInstance 必须是无参的构造函数,且是public
(7)两个类型进行指向,继承
Type typeicmd = typeof(IDbCommand);
Type typecmd=typeof(DbCommand);
Type typesqlcmd=typeof(SqlCommand);
//当前的实例是否可以指向实例 主 谓关系
Console.WriteLine(typeicmd.IsAssignableFrom(typecmd));
//判断当前类型是否是后面类型的子类
Console.WriteLine(typesqlcmd.IsSubclassOf(typecmd));
(8)如何给类型进行赋值
Type typep = typeof(Person); //获取类的类型
object obj1 = Activator.CreateInstance(typep);//把类型转换成对象
PropertyInfo proname = typep.GetProperty("name"); //通过类型获取属性
proname.SetValue(obj1, "zhangsan", null);//是哪个对象的属性
MethodInfo meth = typep.GetMethod("Say");
meth.Invoke(obj1, null); //调用方法,是哪个对象的方法
Console.ReadKey();
class Person
{
public string name { get; set; }
public int Age { get; set; }
public void Say()
{
Console.WriteLine("说了一声{0}{1}", name, Age);
}
}
★★★★★如何调用私有的方法 ★★★★★不到万不得已,最好别用
只要在方法调用的后面跟上 BindingFlags.NonPublic | BindingFlags.Instance
MethodInfo meth = typep.GetMethod("Say",BindingFlags.NonPublic | BindingFlags.Instance); //假设Say是一个私有的方法
meth.Invoke(obj1, null); //调用方法,是指调用哪个对象的方法
(8)制作一个可以动态根据dll进行的菜单栏
menuStrip1.Items.Add("工具");//最上面进行添加菜单栏
工具ToolStripMenuItem.DropDownItems.Add("测试");//添加菜单栏的下一级菜单栏
①在接口中声明一个只有返回值的get属性,和一个方法
public interface Icomputer
{
string name { get;}
string Exe(string oldtxt);
}
②声明一个实现接口的类,并且添加接口的引用
public class Computer:Icomputer
{
#region Icomputer 成员
public string name
{
get
{
return "转换为大写";
}
}
public string Exe(string oldtxt)
{
return oldtxt.ToUpper();
}
#endregion
}
③在主程序中添加接口的引用
④加载实现接口的类文件,并且在程序集中获取该类的类型
string file = @"C:\Documents and Settings\Administrator\桌面\C#\动态加载菜单\实现接口\bin\Debug\实现接口.dll";
Assembly assm = Assembly.LoadFile(file);
Type[] type1 = assm.GetExportedTypes();
⑤对类型进行遍历,凡是实现了接口的类型,且不是抽象类的,就进行加载到窗体控件中。
foreach (Type types in type1)
{ //如果类型实现了接口,并且该类型不是抽象类型的话
if (type2.IsAssignableFrom(types) && !types.IsAbstract)
{ //接口指向实现了接口的对象
Icomputer icom = (Icomputer)Activator.CreateInstance(types);
//创建对应的菜单项
ToolStripMenuItem tsm = new ToolStripMenuItem(icom.name);
工具ToolStripMenuItem.DropDownItems.Add(tsm);
tsm.Click+=new EventHandler(tsm_Click);
tsm.Tag = icom;
}
}
⑥写实现的具体代码
void tsm_Click(object sender, EventArgs e)
{
ToolStripMenuItem mi = sender as ToolStripMenuItem;
MessageBox.Show(mi.Text);
Type plugintype = (Type)mi.Tag;
}
(9)如何对用户控件的属性进行标记
①对用户控件的属性进行标记的话,那么首先要声明一个属性
public string NameTel123
{
get;
set;
}
②在属性的上方标记[DisplayName("姓名电话")] 其中DisplayName是类DisplayNameAttribute的简写
(10)如何对用户控件的属性进行标记
Type type = telTextBox1.GetType(); //获取用户控件的类型
foreach (PropertyInfo prop in type.GetProperties()) //对类型的属性进行遍历
{
if (!prop.CanRead) //如果该属性是只读的,那么退出本次循环,执行下一次循环
continue;
object propValue = prop.GetValue(telTextBox1, null); //把类型转换为对象
//获得prop属性上标记的DisplayNameAttribute对象
//因为可能标记多个,所以是数组
object[] attributes =prop.GetCustomAttributes(typeof(DisplayNameAttribute), true);
if (attributes.Length == 1)
{
DisplayNameAttribute dna = (DisplayNameAttribute)attributes[0];
string displayname = dna.DisplayName;
string text = string.Format("{0}={1}\r\n", displayname, propValue);
textBox1.AppendText(text);
}
else
{
string text = string.Format("{0}={1}\r\n", prop.Name, propValue);
textBox1.AppendText(text);
}
}
浙公网安备 33010602011771号