欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# 程序集和反射詳解

 更新時(shí)間:2017年01月17日 08:42:46   作者:鄒瓊俊  
本文主要介紹了C# 程序集和反射的相關(guān)知識(shí)。具有一定的參考價(jià)值,下面跟著小編一起來看下吧

這里我又嘮叨幾句,大家在學(xué)習(xí)的時(shí)候,如看書或者看視頻時(shí)覺得非常爽,因?yàn)楦杏X基本都看得懂也都挺容易的,其實(shí)看懂是一回事,你自己會(huì)動(dòng)手做出來是一回事,自己能夠說出來又是另一回事了。應(yīng)該把學(xué)到的東西變成自己的東西,而不是依樣畫瓢。

在說反射之前,我們先來了解一下什么是程序集?

程序集

程序集是.net中的概念,程序集可以看作是給一堆相關(guān)類打一個(gè)包,相當(dāng)于java中的jar包。

程序集包含:

  • 資源文件
  • 類型元數(shù)據(jù)(描述在代碼中定義的每一類型和成員,二進(jìn)制形式)
  • IL代碼(這些都被封裝在exe或dll中)

exe與dll的區(qū)別。

exe可以運(yùn)行,dll不能直接運(yùn)行,因?yàn)閑xe中有一個(gè)main函數(shù)(入口函數(shù))。

類型元數(shù)據(jù)這些信息可以通過AssemblyInfo.cs文件來自定義。在每一個(gè).net項(xiàng)目中都存在一個(gè)AssemblyInfo.cs文件,代碼格式:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有關(guān)程序集的常規(guī)信息通過以下
// 特性集控制。更改這些特性值可修改
// 與程序集關(guān)聯(lián)的信息。
[assembly: AssemblyTitle("ReflectedDemo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReflectedDemo")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 將 ComVisible 設(shè)置為 false 使此程序集中的類型
// 對(duì) COM 組件不可見。 如果需要從 COM 訪問此程序集中的類型,
// 則將該類型上的 ComVisible 特性設(shè)置為 true。
[assembly: ComVisible(false)]
// 如果此項(xiàng)目向 COM 公開,則下列 GUID 用于類型庫的 ID
[assembly: Guid("7674d229-9929-4ec8-b543-4d05c6500863")]
// 程序集的版本信息由下面四個(gè)值組成: 
//
//   主版本
//   次版本 
//   生成號(hào)
//   修訂號(hào)
//
// 可以指定所有這些值,也可以使用“生成號(hào)”和“修訂號(hào)”的默認(rèn)值,
// 方法是按如下所示使用“*”: 
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

這些信息在哪里體現(xiàn)呢?就在我們程序集的屬性當(dāng)中進(jìn)行體現(xiàn)

我們平時(shí)在安裝一些CS客戶端程序的時(shí)候,在安裝目錄下面會(huì)看見許多的程序集文件。

使用程序集的好處

  • 程序中只引用必須的程序集,減小程序的尺寸。
  • 程序集可以封裝一些代碼,只提供必要的訪問接口。
  • 方便擴(kuò)展。

如何添加程序集的引用?

直接添加程序集路徑或者添加解決方案中的項(xiàng)目引用。

當(dāng)我們需要擴(kuò)展一個(gè)程序的時(shí)候,你可能會(huì)直接在原有的項(xiàng)目中進(jìn)行添加,那這樣的話,如果你的這些代碼想共享給別人使用呢?你就可以打包成一個(gè)程序集,然后別人只要通過引用你這個(gè)程序集就可以進(jìn)行擴(kuò)展了。像我們常見的.net第三方框架庫,如log4net、unity等等。

注意:不能添加循環(huán)引用

什么是添加循環(huán)引用?就是說A項(xiàng)目如果添加了B項(xiàng)目的項(xiàng)目引用,那么此時(shí)B項(xiàng)目不能再添加A項(xiàng)目的項(xiàng)目引用,也就是說添加項(xiàng)目引用時(shí),必須是單向的,像我們常見的三層框架之間的項(xiàng)目引用。

反射

關(guān)于反射,你只要是做.net開發(fā),你就一定天天在用。因?yàn)閂S的智能提示就是通過應(yīng)用了反射技術(shù)來實(shí)現(xiàn)的,還有我們常用的反編譯神器Reflector.exe,看它的名字就知道了。項(xiàng)目中比較常見的,是通過結(jié)合配置文件來動(dòng)態(tài)實(shí)例化對(duì)象,如切換數(shù)據(jù)庫實(shí)例,或者Sprint.net的通過配置文件來實(shí)現(xiàn)依賴注入等。

反射技術(shù)其實(shí)就是動(dòng)態(tài)獲取程序集的元數(shù)據(jù)的功能,反射通過動(dòng)態(tài)加載dll,然后對(duì)其進(jìn)行解析,從而創(chuàng)建對(duì)象,調(diào)用成員。

Type是對(duì)類的描述,Type類是實(shí)現(xiàn)反射的一個(gè)重要的類,通過它我們可以獲取類中的所有信息,包括方法、屬性等。可以動(dòng)態(tài)調(diào)用類的屬性、方法。

反射的出現(xiàn)讓創(chuàng)建對(duì)象的方式發(fā)生了改變,因?yàn)檫^去面完創(chuàng)建對(duì)象都是直接通過new。

dll里面有兩部分東西:IL中間語言和metadate元素?fù)?jù)。

在.NET中反射用到命名空間是System.Reflection,這里我先通過一個(gè)Demo來看反射能做些什么

1、  新建控制臺(tái)項(xiàng)目ReflectedDemo

2、  新建類庫項(xiàng)目My.Sqlserver.Dal

新建兩個(gè)類SqlServerHelper和SqlCmd,前者為共有類,后者為私有類

namespace My.Sqlserver.Dal
{
  public class SqlServerHelper
  {
    private int age = 16;
    public string Name { get; set; }
    public string Query()
    {
      return string.Empty;
    }
  }
  class SqlCmd
  {
  }
}

3、  項(xiàng)目ReflectedDemo,添加My.Sqlserver.Dal的項(xiàng)目引用,我這樣做的目的是為了方便項(xiàng)目ReflectedDemo中的bin目錄中時(shí)刻存在My.Sqlserver.Dal.dll程序集。

using System;
using System.Reflection;
namespace ReflectedDemo
{
  class Program
  {
    static void Main(string[] args)
    {
      //加載程序集文件,在bin目錄中查找
      Assembly assembly = Assembly.Load("My.Sqlserver.Dal");
      Console.WriteLine("----------------Modules----------------------");
      var modules = assembly.GetModules();
      foreach(var module in modules)
      {
        Console.WriteLine(module.Name);
      }
      Console.WriteLine("----------------Types----------------------");
      var types = assembly.GetTypes(); //獲取程序集中所有的類型,包括公開的和不公開的
      foreach(var type in types)
      {
        Console.WriteLine(type.Name);
        Console.WriteLine(type.FullName);
        var members= type.GetMembers(); //獲取Type中所有的公共成員
        Console.WriteLine("----------------members----------------------");
        foreach(var m in members)
        {
          Console.WriteLine(m.Name);
        }
      }
      Console.WriteLine("----------------GetExportedTypes----------------------");
      var exportedTypes = assembly.GetExportedTypes(); //獲取程序集中所有的公共類型
      foreach(var t in exportedTypes)
      {
        Console.WriteLine(t.Name);
      }
      Console.WriteLine("----------------GetType----------------------");
      var typeName= assembly.GetType("SqlServerHelper");//獲取程序集中指定名稱的類型對(duì)象
      Console.WriteLine(typeName.Name);
    }
  }
}

動(dòng)態(tài)創(chuàng)建對(duì)象

通過ass.CreateInstance(string typeName) 和Activator.CreateInstance(Type t)方法

他們之間的區(qū)別

ass.CreateInstance(string typeName) 會(huì)動(dòng)態(tài)調(diào)用類的無參構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象,返回值就是創(chuàng)建的對(duì)象,如果沒有無參構(gòu)造函數(shù)就會(huì)報(bào)錯(cuò)。

Assembly assembly = Assembly.Load("My.Sqlserver.Dal");
object obj = assembly.CreateInstance("My.Sqlserver.Dal.SqlServerHelper");
Console.WriteLine(obj.GetType().ToString());

如果我們來修改SqlServerHelper類的代碼,添加如下構(gòu)造函數(shù):

    public SqlServerHelper(int age)
    {
      this.age = age;
    }

這個(gè)時(shí)候再來運(yùn)行創(chuàng)建實(shí)例的代碼就會(huì)報(bào)錯(cuò)了,而編譯時(shí)是不報(bào)錯(cuò)的。

所以我們一般推薦使用Activator.CreateInstance方法來創(chuàng)建反射對(duì)象,因?yàn)榇朔椒ㄓ性S多重載,支持將參數(shù)傳遞給構(gòu)造函數(shù)。

此時(shí)再調(diào)用就不會(huì)出現(xiàn)異常了。

Type類中有三個(gè)用得比較多的方法:

  • bool IsAssignableFrom(Type t):是否可以從t賦值,判斷當(dāng)前的類型變量是不是可以接受t類型變量的賦值。
  • bool IsInstanceOfType(object o):判斷對(duì)象o是否是當(dāng)前類的實(shí)例,當(dāng)前類可以是o的類、父類、接口
  • bool IsSubclassOf(Type t):判斷當(dāng)前類是否是t的子類

Type類中還有一個(gè)IsAbstract屬性:判斷是否為抽象的,包含接口。

它們常用的原因是我們通過反射可以取到的東西太多了,我們需要對(duì)數(shù)據(jù)進(jìn)行過濾。

添加類BaseSql,讓類SqlServerHelper繼承自BaseSql

然后查看調(diào)用代碼:

      bool result = typeof(BaseSql).IsAssignableFrom(typeof(SqlServerHelper));
      Console.WriteLine(result);

   SqlServerHelper _SqlServerHelper = new SqlServerHelper(1);
   bool result = typeof(SqlServerHelper).IsInstanceOfType(_SqlServerHelper);
   Console.WriteLine(result);

      SqlServerHelper _SqlServerHelper = new SqlServerHelper(1);
      bool result = typeof(SqlServerHelper).IsSubclassOf(typeof(BaseSql));
      Console.WriteLine(result);

項(xiàng)目中常用的利用反射來動(dòng)態(tài)切換數(shù)據(jù)庫Demo:

新建類庫項(xiàng)目My.Sql.IDal,并添加接口ISqlHelper。通過接口來實(shí)現(xiàn)數(shù)據(jù)庫操作的類的解耦,因?yàn)榻涌谑浅橄蟮摹?/p>

  public interface ISqlHelper
  {
    string Query();
  }

添加類庫項(xiàng)目My.MySql.Dal,并新增類MySqlHelper.cs

My.Sqlserver.Dal、My.MySql.Dal項(xiàng)目分別添加對(duì)項(xiàng)目My.Sql.IDal的引用。讓SqlServerHelper繼承自接口ISqlHelper

public class MySqlHelper : ISqlHelper
  {
    public string Query()
    {
       return this.GetType().ToString();
    }
  }
  public class SqlServerHelper :ISqlHelper
  {
    private int age = 16;
    public string Name { get; set; }
    public string Query()
    {
      return this.GetType().ToString();
    }
  }

添加App.config配置項(xiàng)

 <appSettings>
  <add key="DBName" value="My.Sqlserver.Dal,SqlServerHelper"/>
 </appSettings>

ReflectedDemo項(xiàng)目中Program.cs調(diào)用代碼:

string str = ConfigurationManager.AppSettings["DBName"];
      string strAssembly = str.Split(',')[0];
      string strClass=str.Split(',')[1];
      Assembly assembly = Assembly.Load(strAssembly);
      Type t = assembly.GetType(strAssembly + "." + strClass);
      ISqlHelper obj = Activator.CreateInstance(t) as ISqlHelper;
      Console.WriteLine(obj.Query());

這樣每次需要切換數(shù)據(jù)庫時(shí),只要修改配置文件就可以了。

項(xiàng)目結(jié)構(gòu):

注意:反射雖然很強(qiáng)大,但卻是比較耗性能的,所以一般和緩存結(jié)合起來使用。

項(xiàng)目源碼:ReflectedDemo.zip

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

最新評(píng)論