zoukankan      html  css  js  c++  java
  • C#反射的实现

    一,什么是反射?

    1,System.Reflection 命名空间中的类与 System.Type 使你能够获取有关加载的程序集和其中定义的类型的信息,如类、接口和值类型。 可以使用反射在运行时创建、调用和访问类型实例。

    2,System.Type 类对于反射起着核心的作用。 当反射请求加载的类型时,公共语言运行时将为它创建一个 Type。 您可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。

    3,动态的创建类型的实例,将类型邦定到现有对象,或从现有对象中获取类型 (动态获取程序集)

    4,应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射 


    二,简单工厂的设计

    项目各层之间的引用情况:

    FanSheLK引用IFanSheLK

    DataBLL引用IFanSheLK和DataDemo

    DataDemo引用IFanSheLK

    MvcTest引用DataBLL,FanSheLK

    三,代码如下

    FanSheLK代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using IFanSheLK;
    
    namespace FanSheLK
    {
        public class Class1 : IClass1
        {
            public void aa()
            {
                Console.WriteLine("aa");
            }
        }
    }

    IFanSheLK的代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace IFanSheLK
    {
        public interface IClass1
        {
            void aa();
        }
    }

    DataDemo代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using IFanSheLK;
    using System.Reflection;
    
    namespace DataDemo
    {
        public sealed class DataAccess
        {
            private static readonly string AssemblyPath = "FanSheLK";
            public DataAccess()
            { }
    
            #region CreateObject
    
            //不使用缓存
            private static object CreateObjectNoCache(string AssemblyPath, string classNamespace)
            {
                try
                {
                    //使用 Assembly 来定义和加载程序集,加载程序集清单中列出的模块,以及在此程序集中定位一个类型并创建一个它的实例。
                    object objType = Assembly.Load(AssemblyPath).CreateInstance(classNamespace);
                    return objType;
                }
                catch(Exception e)
                {
                    return e.Message;
                }
    
            }
            #endregion
    
    
    
            /// <summary>
            /// 创建数据层接口。
            /// </summary>
            public static IClass1 CreateUser()
            {
                string ClassNamespace = "FanSheLK.Class1";
                object objType = CreateObjectNoCache(AssemblyPath, ClassNamespace);
                return (IClass1)objType;
            }
    
        }
    }

    DataBLL的代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using DataDemo;
    using IFanSheLK;
    
    namespace DataBLL
    {
        public class Class1
        {
            public readonly IClass1 a = DataAccess.CreateUser();
            public Class1() {
               
            }
            public string Test() {
                return "成功";
            }
        }
    }

    MVC的HomeController.cs的调用实现

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using DataBLL;
    
    namespace MvcTest.Controllers
    {
        public class HomeController : Controller
        {
            //
            // GET: /Home/
    
            public ActionResult Index()
            {
                Class1 a = new Class1();
                a.Test();
                return View();
            }
    
        }
    }

    三,然而在实现反射的过程中最容易出现的问题就是:未能加载文件或程序集“xxx(FanSheLK)”或它的某一个依赖项。系统找不到指定的文件。

    这是由于反射中的这个造成的Assembly.Load(AssemblyPath).CreateInstance(classNamespace);,切确来说是Assembly.Load(AssemblyPath)这找不到要反射的类库

    PS:    到这个时候就要检查下你加载DLL路径是否错误,即DLL文件存在,但加载路径不正确

    但是在此之前你要明白:Assembly.Load()要加载的DLL路径究竟是哪里!!!!!!!!!!

    根据问题,有以下猜测:

    1》在反射方法类库的inDebug下?(即我项目的DataDemoinDebug)

    2》在MVC站点的inDebug下?(即我项目的MvcTestinDebug)

    3》在反射实现类库的inDebug下?(即我项目的DataBLLinDebug)

    解决如下:

    1》在反射方法类库(DataDemo),添加要反射类库(FanSheLK)的引用,将生成的FanSheLK.dll到项目的DataDemoinDebug下,但是经过实验证明,这是错误的,一样提示:未能加载文件或程序集“xxx(FanSheLK)”或它的某一个依赖项。系统找不到指定的文件

    2》在MVC站点添加引用,添加要反射类库(FanSheLK)的引用,将生成的FanSheLK.dll到项目的inDebug下,神奇的结果出现了,方法Assembly.Load成功加载了,但是还需要继续实验下去。。。。

    3》在反射实现类库(DataBLL),添加引用,添加要反射类库(FanSheLK)的引用,将生成的FanSheLK.dll到项目的inDebug下,神奇的结果又出现了,方法Assembly.Load成功加载了

    这样又出现新的问题:为什么会有两种假设成功?根据以上两种情况分别引用,我们查看他们的相同的地方和不相同的地方

    1》先将反射实现类库(DataBLL)和在MVC站点的项目的inDebug下DLL都删掉

    2》在MVC站点添加引用,添加要反射类库(FanSheLK)的引用,项目重新生成,我们会发现FanSheLK.dll会在MVC站点的inDebug下生成,而反射实现类库(DataBLL)并没有

    3》在反射实现类库(DataBLL),添加引用,添加要反射类库(FanSheLK)的引用,项目重新生成,在这一次,我们会发现FanSheLK.dll会在MVC站点的inDebug下和反射实现类库(DataBLL)下生成

    4》经过以上对比我们发现共同点:FanSheLK.dll会在MVC站点的inDebug下生成,那我们把他删掉,测试

    5》得出结论:Assembly.Load()寻找的地址是在MVC站点的inDebug下,则如果反射出现:未能加载文件或程序集“xxx(FanSheLK)”或它的某一个依赖项。系统找不到指定的文件。错误时:我们应该查看该目录下是否存在反射类库的DLL

    PS:为什么在反射实现类库(DataBLL),添加引用,添加要反射类库(FanSheLK)的引用,项目重新生成,FanSheLK.dll会在MVC站点的inDebug下和反射实现类库(DataBLL)下同时生成?

    原因是我的DataBLL被MVC站点引用,所以会生成DataBLL的引用的DLL,然而这样的引用在VS中执行没问题,然而如果使用IIS发布出去就会出现反射失败,这又是为什么呢???

    原因:也是查找不到路径,如果需要执行成功,我们就要在MVC站点下添加反射库(FanSheLK)的引用,而不是在反射实现库(DataBLL)中添加(FanSheLK)的引用

    四,命名空间或者路径,经过排查发现都正确,但是还是报这个错误:调用的目标发生了异常。这时候问题可能就是在调用的类,就是项目的反射类库(FanSheLK)

    1》有可能该类库中的反射类定义的属性出现错误

    2》有可能反射类库(FanSheLK)引用了其他类库,出现继承,然而反射却找不到反射类库(FanSheLK)引用类库的路径

    五,如果类库存在实体模型 会出现错误:指定的命名连接在配置中找不到、非计划用于 EntityClient 提供程序或者无效。

    1》原因:因为实体模型的构造函数方法失败

        /// <summary>
            /// 请使用应用程序配置文件的“JXCEntities”部分中的连接字符串初始化新 JXCEntities 对象。
            /// </summary>
            public JXCEntities() : base("name=JXCEntities", "JXCEntities")
            {
                this.ContextOptions.LazyLoadingEnabled = true;
                OnContextCreated();
            }

    解决方法:将实体模型的连接写在站点(MVC的Web.config)的配置文件下,则读取配置文件成功

      <connectionStrings>
        <add name="JXCEntities" connectionString="metadata=res://*/Entities.csdl|res://*/Entities.ssdl|res://*/Entities.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.;initial catalog=XXX;user id=XX;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
      </connectionStrings>

     五,反射构造带参的例子

    1》传递变量

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    
    namespace FanShe3
    {
        class Test
        {
            public Test(string Say)
            {
                Console.WriteLine(Say);
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                Test t;
                string Say = "哈哈!!创建成功";
                //开始创建反射,这个是获取当前程序集的意思,如果需要反射类库可以使用Assembly.Load的方法
                Assembly asm = Assembly.GetExecutingAssembly();
                //需要注意的地方是,如果反射的构造函数带参只是一个,这里创建的也必须是一个参数的Object数组,而且顺序也必须和构造函数一样
                object[] Obj = new object[1];
                Obj[0] = Say;
                t = (Test)asm.CreateInstance("FanShe3.Test", true, BindingFlags.Default, null, Obj, null, null);
    
                Console.ReadKey();
            }
        }
    }

    2》传递对象

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    
    namespace FanShe4
    {
        class Test
        {
            public Test(Test2 t2)
            {
                t2.Say();
            }
        }
    
        public class Test2
        {
            public void Say()
            {
                Console.WriteLine("哈哈!!创建成功");
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Test t;
                Test2 t2 = new Test2();
                //开始创建反射,这个是获取当前程序集的意思,如果需要反射类库可以使用Assembly.Load的方法
                Assembly asm = Assembly.GetExecutingAssembly();
                //需要注意的地方是,如果反射的构造函数带参只是一个,这里创建的也必须是一个参数的Object数组,而且顺序也必须和构造函数一样
                object[] Obj = new object[1];    
                Obj[0] = t2;
                t = (Test)asm.CreateInstance("FanShe4.Test", true, BindingFlags.Default, null, Obj, null, null);
    
                Console.ReadKey();
            }
        }
    
    
    }

    综上,如果出现错误:有路径问题,传参数的数量不对等

     反射由浅入深了解学习(一)

  • 相关阅读:
    桥接,NAT,Host Only的区别
    PHP并发IO编程之路
    Git SSH Key 生成步骤
    composer安装学习
    db file sequential read等待事件的一点研究
    多个hints 怎么写?
    再次遭遇笛卡尔积
    pl/sql 在一个程序块里打印日志输出到表格
    pl/sql 程序块里打印问题
    利用ordered hints优化SQL
  • 原文地址:https://www.cnblogs.com/May-day/p/6639096.html
Copyright © 2011-2022 走看看