[AaronYang]C#人爱学不学11-反射加载dll的demo

Load方法:CLR通过调用System.Rreflection.Assemblly类的静态方法来显示加载程序集。

public static Assembly Load(AssemblyName assemblyRef);
public static Assembly Load(string assemblyString);

LoadFrom方法:此方法首先打开程序集,并通过 public static AssemblyName GetAssemblyName(string assemblyFile);方法提取到程序集名称,然后再使用Load方法加载程序集。

public static Assembly LoadFrom(string path);

ReflectionOnlyLoad方法:加载程序集,只是获取程序集的相关信息。但CLR禁止此程序集中的代码执行

public static Assembly ReflectionOnlyLoad(string assemblyString);

ReflectionOnlyLoadFrom

public static Assembly ReflectionOnlyLoadFrom(string path);

System.Type.GetType方法 :字符串必须执行的是全名,对于基元类型不能识别,识别CLR类型。

public static Type GetType(string typeName);

System.Type.ReflectionOnlyGetType:只是显示反射上下文内容,不能执行代码。

public static Type ReflectionOnlyGetType(string typeName, bool throwIfNotFound, bool ignoreCase);

typeof()

static Encryption(object o)
        {
             //早期绑定:o.GetType()  
             //晚期绑定typeof
            if (o.GetType() == typeof(Encryption))
            {
            }
 }

创造类型实例

System.Activator.CreateInstance

public static object CreateInstance(Type type);
public static ObjectHandle CreateInstance(string assemblyName, string typeName);

上面的方法返回值有的是ObjectHandle类型,此类型允许将一个AppDomian中的对象传送到另一个AppDomian而且不需要具体化哪个对象。如果需要具体化具体的类型就可以调用 Unwrap()方法。

System.Activator.CreateComInstanceFrom:程序集和类型都是字符串直接指定,不过,程序集需要使用LoadFrom方法来加载得到程序集,并且提取名称作为参数传递。当然对于返回值我们也需要调用Unwrap()进行具体化。

public static ObjectHandle CreateComInstanceFrom(string assemblyName, string typeName);
System.Reflection.Assembly assy= System.Reflection.Assembly.LoadFrom("");
System.Activator.CreateComInstanceFrom(assy.FullName, "Encryption");

MemberInfo的成员组成

DeclaringType:声明方法的类

ReflectedType:当前的反射类

public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            System.Reflection.MemberInfo[] mi = typeof(MyType).GetMembers();            

            foreach (var m in mi)
            {
               var dt=  m.DeclaringType;//ToSting()
               var rt = m.ReflectedType;//Equal()
            }
        }
    }
    public sealed class MyType
    {

        public override string ToString()
        {
            return null;
        }
    }

BindingFlags:筛选返回的成员种类

我们可以调用Type的 GetMethod、GetProperty、GetNestedType各种Get。

我们可以组合BindingFlags,来筛选我们需要的东西。

我们可以找出我们需要的东东,然后我们可以进行调用。调用属性、方法、构造函数等等。

调用FieldInfo,可以获取或者设置字段的值;

调用ConstructorInfo,可以向构造传递实参,从而构造类型的一个实例;

调用MethodInfo,可以通过传递实参来调用方法,并返回它的返回值;

调用PropertyInfo,可以调用属性的get和set访问其方法。

调用方法

public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, CultureInfo culture);

调用此方法可以在成员类型里搜索一个匹配的类型成员,如果没找到,抛出异常。如果找到,就会调用此成员。我们可以归纳以上行为为两个阶段:绑定和调用。

我们调用一个绑定器方法时,首先我们传递 目标成员 name、方法的所有参数类型 args 、指定的 BindingFlags invokeAttr 。

参数 name :目标成员。名字

参数 invokeAttr :这些位标识的组合可以帮助我们更好的定位我们的成员 IgnoreCase = 1, DeclaredOnly = 2,Instance = 4,Static = 8,Public = 16等

参数 binder :它的类型从System.Relflection.Binder 抽象类型派生的,从Binder派生的类型,封装了InverMember方法确定绑定类型的规则。编译器为我们定义了System.DefaultBinder 的实际类型可以为我们使用。可以帮助我们自动的类型转换。

参数 target : 目标成员所在类的实例的一个引用。静态类 =null。

参数 args: 传递的参数。

参数 culture: 如果有自己的绑定器可以使用此参数,如果前面参数使用了System.DefaultBinder,culture参数就可以省略了。

InvokeMember方法可以,访问任何成员。但是如果多次调用,我们就需要多次进行绑定并调用,比较损耗性能。我们可以使用


实践

环境 vs2015

新建控制台 DLLLoadDemo

新建IServices类库,放接口

新建JDPayServices类库放实现

2016-2-5  ===== AYUI       www.ayjs.net      AY      ======

DLLLoadDemo和IServices项目生成目录都改到上级目录的bin下

blob.png

JDPayServices放到bin下的PayServices文件夹下

IService下新建IPayService

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IServices
{
    public interface IPayService
    {
       string PayName { get; set; }
       
        string UserId { get; set; }

        string BusinessId { get; set; }

        decimal Money { get; set; }

        DateTime OrderDate { get; set; }

        string NotifyUrl { get; set; }

        string CompleteUrl { get; set; }


        void Pay();

        void Pay(string remark);
        
           bool Notify();
    }
}

在JDPayService新建统一名字的PayService,引用IServices项目,然后继承IPayService,并实现

blob.png

using IServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JDPayService
{
    public class PayService : IPayService
    {
     public PayService() { }
    
     public PayService(string payname,string userid,string businessid,decimal money,DateTime orderDate,string notifyUrl,string completeUrl)
        {
            this.PayName = payname;
            this.UserId = userid;
            this.BusinessId = businessid;
            this.Money = money;
            this.OrderDate = orderDate;
            this.NotifyUrl = notifyUrl;
            this.CompleteUrl = completeUrl;
        }
    
        public string PayName { get; set; }
        public string UserId { get; set; }

        public string BusinessId { get; set; }

        public decimal Money { get; set; }

        public DateTime OrderDate { get; set; }

        public string NotifyUrl { get; set; }

        public string CompleteUrl { get; set; }



        public void Pay()
        {
            Console.WriteLine("============="+ PayName +"=============");
            Console.WriteLine(string.Format("{0}:{1}向{2}支付了{3},成功!", OrderDate.ToString("F"), UserId, BusinessId, Money.ToString("C")));
            Console.WriteLine("=============交易结束=============");
        }

        public void Pay(string remark)
        {
            Console.WriteLine("=============" + PayName + "=============");
            Console.WriteLine(string.Format("{0}:{1}向{2}支付了{3},成功!",OrderDate.ToString("F"),UserId,BusinessId,Money.ToString("C")));
            Console.WriteLine("备注:"+remark);
            Console.WriteLine("=============交易结束=============");
        }

        public bool Notify()
        {
            Console.WriteLine("已经通知:"+NotifyUrl);
            return true;
        }
    }
}

调整引用的IServices.dll的属性,不要复制到本地

blob.png

DLLLoadDemo引用IServices,重新生成解决方案

blob.png

blob.png

准备工作完成了,接下来,在DLLLoadDemo代码里面写 反射代码,学习。


 获取当前主程序所在路径

string hostFilePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)+ "/PayServices";

然后我们获得所有的支付方式dll

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DLLLoadDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //获取当前主程序所在路径
            string hostFilePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)+ "/PayServices";
            //获取dll路径
            string[] dlls = System.IO.Directory.GetFiles(hostFilePath, "*.dll");

            foreach (string dll in dlls)
            {
                Console.WriteLine(dll);
            }
            Console.ReadLine();


        }
    }
}

运行效果:

blob.png

获得程序集名字 Name和FullName

blob.png

一个程序集多个类和其他的成员组成的

   //获取程序集中所有公共类
                    Type[] types = assembly.GetExportedTypes();
                    foreach (var item in types)
                    {
                        Console.WriteLine("Type name :{0}", item.FullName);

                    }

blob.png

断点查看,还有很多其他属性,你可以过滤

blob.png

判断是不是继承IPayService的类,是的话,获得所有成员

   foreach (var item in types)
                    {
                        Console.WriteLine("Type name :{0}", item.FullName);
                        if (item.IsClass && typeof(IServices.IPayService).IsAssignableFrom(item))
                        {
                            //获取当前类中公共成员
                            System.Reflection.MemberInfo[] members = item.GetMembers();

                        }
                    }

构造实例

blob.png

   //获取程序集中所有公共类
                    Type[] types = assembly.GetExportedTypes();
                    foreach (var item in types)
                    {
                        Console.WriteLine("Type name :{0}", item.FullName);
                        if (item.IsClass && typeof(IServices.IPayService).IsAssignableFrom(item))
                        {
                            //获取当前类中公共成员
                            System.Reflection.MemberInfo[] members = item.GetMembers();
                            IServices.IPayService pay = (IServices.IPayService)System.Activator.CreateInstance(item,"京东支付","ayBuy","ayBus",100.00M,DateTime.Now,"http://www.ayjs.net/rest/no1", "http://www.ayjs.net/rest/nocomplete");
                            if (pay != null) {
                                pay.Pay("ay购买BB鸡,875556003@qq.com");
                            }
                        }
                    }

调用dll中符合接口的约定的 方法

blob.png

获得属性:

 Console.WriteLine("----属性----");
                            System.Reflection.PropertyInfo[] ppinfo = item.GetProperties();

                            foreach (var p in ppinfo)
                            {
                                Console.WriteLine("属性: {0} (get:{1},set:{2})", p.Name, p.CanRead.ToString(), p.CanWrite.ToString());
                                Console.WriteLine("{0}={1}", p.Name,p.GetValue(pay,null));
                            }

blob.png

获得字段:

我们先在PayService加上几个测试字段

               private const string version = "1.2.5.7";
        public const string author = "ay";
        public readonly static int age = 25;
        public bool isRead = false;
        public string wuString;
        public string nullString = null;
  Console.WriteLine("----字段----");
                            System.Reflection.FieldInfo[] fields = item.GetFields();
                            foreach (var f in fields)
                            {
                                object v = f.GetValue(pay);
                                Console.WriteLine("普通字段 {0}  {1} {2}", f.Name, f.FieldType.ToString(),v==null?"空":v.ToString());

                             
                            }

效果图:

blob.png

只读取了 非private的字段。

稍微修改

  System.Reflection.FieldInfo[] fields = item.GetFields();
                            foreach (var f in fields)
                            {
                                object v = f.GetValue(pay);
                         
                                //Console.WriteLine("普通字段 {0}  {1} {2}", f.Name, f.FieldType.ToString(),v==null?"空":v.ToString());
                                Console.WriteLine("public {0}{1} {2} {3}",f.IsStatic?"static ":"", f.FieldType.ToString(), f.Name, v == null ? " 空 " : "="+v.ToString());

                            }

blob.png

2016-2-5  ======== AYUI       www.ayjs.net      AY         ===============

方法

          //方法
                            Console.WriteLine("----方法----");

                            System.Reflection.MethodInfo[] methodsinfo = item.GetMethods();
                            foreach (var m in methodsinfo)
                            {
                                //返回后打印出类中成员的类型(方法的返回值类型)极其方法名称
                                Console.WriteLine("  " + m.ReturnType.Name + "  " + m.Name + "");//ReturnType获取此方法的返回类型
                            }

blob.png

发现了2个pay,这是个重载的方法,所以调用,我们要知道参数,决定调用哪个

获得方法的参数,显示

         //方法
                            Console.WriteLine("----方法----");

                            System.Reflection.MethodInfo[] methodsinfo = item.GetMethods();
                            foreach (var m in methodsinfo)
                            {
                                //返回后打印出MyClass类中成员的类型(方法的返回值类型)极其方法名称
                                Console.Write("  " + m.ReturnType.Name + "  " + m.Name + "(");//ReturnType获取此方法的返回类型

                                ParameterInfo[] pi = m.GetParameters();//获得方法的参数
                                for (int i = 0; i < pi.Length; i++)
                                {
                                    Console.Write(pi[i].ParameterType.Name + "   " + pi[i].Name);//ParameterType 获取该参数的Type(类型)
                                    if (i + 1 < pi.Length)
                                    {
                                        Console.Write(", ");
                                    }

                                }
                                Console.Write(")");
                                Console.WriteLine();
                            }

ay的效果图:

blob.png

这里它把属性的方法也放出来了,父类的方法也是

ay的方法筛选 BindingFlags

  System.Reflection.MethodInfo[] methodsinfo = item.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
                            foreach (var m in methodsinfo)
                            {
                                //返回后打印出MyClass类中成员的类型(方法的返回值类型)极其方法名称
                                Console.Write("  " + m.ReturnType.Name + "  " + m.Name + "(");//ReturnType获取此方法的返回类型

                                ParameterInfo[] pi = m.GetParameters();//获得方法的参数
                                for (int i = 0; i < pi.Length; i++)
                                {
                                    Console.Write(pi[i].ParameterType.Name + "   " + pi[i].Name);//ParameterType 获取该参数的Type(类型)
                                    if (i + 1 < pi.Length)
                                    {
                                        Console.Write(", ");
                                    }

                                }
                                Console.Write(")");
                                Console.WriteLine();
                            }

blob.png

调用方法

blob.png

代码:

 System.Reflection.MethodInfo[] methodsinfo = item.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
                            foreach (var m in methodsinfo)
                            {

                                //demo2   www.ayjs.net
                                if (m.Name == "Pay")
                                {
                                    ParameterInfo[] pi = m.GetParameters();//获得方法的参数
                                    if (pi.Count() == 1)
                                    {
                                        object[] objs = new object[] { "ay买了个iphone7是个,是个模型" };
                                        m.Invoke(pay, objs);
                                    }
                                    else if (pi.Count() == 0)
                                    {
                                        m.Invoke(pay, null);
                                    }
                                    Console.WriteLine();
                                }


                            }

使用类型的InvokeMember方法,重载也不需要考虑了,自动识别,但是调用多了,性能肯定不好。

blob.png

                //demo3
                            object[] para = new object[] { "ay买了个诺基亚,砸了一天的夏威夷果" };
                            item.InvokeMember("Pay", System.Reflection.BindingFlags.InvokeMethod, null, pay, para);

属性赋值:

     //属性赋值
                            //获取指定名称的属性
                            System.Reflection.PropertyInfo propertyInfo = item.GetProperty("Money");
                            propertyInfo.SetValue(pay, 520.00M, null); //给对应属性赋值
                            decimal value_New = (decimal)propertyInfo.GetValue(pay, null);
                            Console.WriteLine("Money新值:"+value_New.ToString("C"));

blob.png

=============好了,先到这里,这是反射基础,后面还有Emit,泛型,dynamic,表达式树,委托的反射创建等 等

下面是我看到的一个DataTable里的数据转到List<T>的数据的DEMO

/// <summary>
    /// 将datatable装入指定类型的集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GenericList<T>:List<T>
    {
        public GenericList(DataTable dt, string  f)
        {
            System.Type tt = System.Type.GetType(f);//获取指定名称的类型
            object ff = Activator.CreateInstance(tt, null);//创建指定类型实例
            PropertyInfo[] fields = ff.GetType().GetProperties();//获取指定对象的所有公共属性
            foreach (DataRow dr in dt.Rows)
            {
                object obj = Activator.CreateInstance(tt, null);
                foreach (DataColumn dc in dt.Columns)
                {
                    foreach (PropertyInfo t in fields)
                    {
                        if (dc.ColumnName == t.Name)
                        {
                            t.SetValue(obj, dr[dc.ColumnName], null);//给对象赋值
                            continue;
                        }
                    }

                }
                this.Add((T)obj);//将对象填充到list集合
            }
        }
    }

}

这里的f是个类型字符串

 GenericList<Employee> list1 = new GenericList<Employee>(dt, "MvcApplication2.Models.Employee");

但是这里我建议不传字符串,而是传个type类型过去

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值