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》在反射方法類庫的\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,然而這樣的引用在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();
        }
    }


}

 

綜上,如果出現錯誤:有路徑問題,傳參數的數量不對等

 反射由淺入深了解學習(一)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM