一,什么是反射?
1,System.Reflection 命名空间中的类与 System.Type 使你能够获取有关加载的程序集和其中定义的类型的信息,如类、接口和值类型。 可以使用反射在运行时创建、调用和访问类型实例。
2,System.Type 类对于反射起着核心的作用。 当反射请求加载的类型时,公共语言运行时将为它创建一个 Type。 您可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。
3,动态的创建类型的实例,将类型邦定到现有对象,或从现有对象中获取类型 (动态获取程序集)
4,应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射
二,简单工厂的设计
项目各层之间的引用情况:
FanSheLK引用IFanSheLK
DataBLL引用FanSheLK,IFanSheLK和DataDemo
DataDemo引用IFanSheLK
MvcTest引用DataBLL
三,代码如下
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》在反射方法类库的\bin\Debug下?(即我项目的DataDemo\bin\Debug)
2》在MVC站点的\bin\Debug下?(即我项目的MvcTest\bin\Debug)
3》在反射实现类库的\bin\Debug下?(即我项目的DataBLL\bin\Debug)
解决如下:
1》在反射方法类库(DataDemo),添加要反射类库(FanSheLK)的引用,将生成的FanSheLK.dll到项目的DataDemo\bin\Debug下,但是经过实验证明,这是错误的,一样提示:未能加载文件或程序集“xxx(FanSheLK)”或它的某一个依赖项。系统找不到指定的文件
2》在MVC站点添加引用,添加要反射类库(FanSheLK)的引用,将生成的FanSheLK.dll到项目的\bin\Debug下,神奇的结果出现了,方法Assembly.Load成功加载了,但是还需要继续实验下去。。。。
3》在反射实现类库(DataBLL),添加引用,添加要反射类库(FanSheLK)的引用,将生成的FanSheLK.dll到项目的\bin\Debug下,神奇的结果又出现了,方法Assembly.Load成功加载了
这样又出现新的问题:为什么会有两种假设成功?根据以上两种情况分别引用,我们查看他们的相同的地方和不相同的地方
1》先将反射实现类库(DataBLL)和在MVC站点的项目的\bin\Debug下DLL都删掉
2》在MVC站点添加引用,添加要反射类库(FanSheLK)的引用,项目重新生成,我们会发现FanSheLK.dll会在MVC站点的\bin\Debug下生成,而反射实现类库(DataBLL)并没有
3》在反射实现类库(DataBLL),添加引用,添加要反射类库(FanSheLK)的引用,项目重新生成,在这一次,我们会发现FanSheLK.dll会在MVC站点的\bin\Debug下和反射实现类库(DataBLL)下生成
4》经过以上对比我们发现共同点:FanSheLK.dll会在MVC站点的\bin\Debug下生成,那我们把他删掉,测试
5》得出结论:Assembly.Load()寻找的地址是在MVC站点的\bin\Debug下,则如果反射出现:未能加载文件或程序集“xxx(FanSheLK)”或它的某一个依赖项。系统找不到指定的文件。错误时:我们应该查看该目录下是否存在反射类库的DLL
PS:为什么在反射实现类库(DataBLL),添加引用,添加要反射类库(FanSheLK)的引用,项目重新生成,FanSheLK.dll会在MVC站点的\bin\Debug下和反射实现类库(DataBLL)下同时生成?
原因是我的DataBLL被MVC站点引用,所以会生成DataBLL的引用的DLL,如果是隔着多层类库就不行(如:站点引用A库,A库引用B库,B库引用C库,站点会生成A.DLL和B.DLL而不会生成C.DLL),但是这在类库中并不会(如A库引用B库,A库编译是并不会将B库的引用编译)