首頁 後端開發 C#.Net教程 C#程式集與反射的圖文程式碼詳解

C#程式集與反射的圖文程式碼詳解

Mar 29, 2017 am 11:45 AM
c# 反射

本文主要介紹了C# 程式集和反射的相關知識。具有一定的參考價值,以下跟著小編一起來看下吧

這裡我又嘮叨幾句,大家在學習的時候,如看書或者看影片時覺得非常爽,因為感覺基本上都看得懂也都挺容易的,其實看懂是一回事,你自己會動手做出來是一回事,自己能夠說出來又是另一回事了。應該把學到的東西變成自己的東西,而不是照樣畫瓢。

在說反射之前,我們先來了解什麼是程式集?

程式集

程式集是.net中的概念,程式集可以看成是給一堆相關類別打一個包,相當於java中的jar包。

程式集包含:

  • 資源檔案

  • #類型元資料(描述在程式碼中定義的每一個類型和成員,二進位形式)

  • IL程式碼(這些都已封裝在exe或dll中)

exe與dll的區別。

exe可以運行,dll不能直接運行,因為exe中有一個main函數(入口函數)。

類型元資料這些資訊可以透過AssemblyInfo.cs檔案來自訂。在每一個.net專案中都存在一個AssemblyInfo.cs文件,程式碼格式:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("ReflectedDemo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReflectedDemo")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("7674d229-9929-4ec8-b543-4d05c6500863")]
// 程序集的版本信息由下面四个值组成: 
//
//   主版本
//   次版本 
//   生成号
//   修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: 
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
登入後複製

這些資訊在哪裡體現呢?就在我們組件的屬性當中進行體現

我們平時在安裝一些CS客戶端程式的時候,在安裝目錄下面會看見許多的程序集檔。

使用組件的好處

  • 程式中只引用必須的組件,減少程式的尺寸。

  • 組件可以封裝一些程式碼,只提供必要的存取介面。

  • 方便擴充。

如何新增組件的參考?

直接新增組件路徑或新增解決方案中的項目參考。

當我們需要擴展一個程式的時候,你可能會直接在原有的專案中進行添加,那麼這樣的話,如果你的這些程式碼想共享給別人使用呢?你就可以打包成一個程式集,然後別人只要引用你這個程式集就可以進行擴充了。像我們常見的.net第三方框架庫,如log4net、unity等等。

注意:不能加入循環引用

什麼是新增循環參考?就是說A項目如果添加了B項目的項目引用,那麼此時B項目不能再添加A項目的項目引用,也就是說添加項目引用時,必須是單向的,像我們常見的三層框架之間的項目引用。

反射

關於反射,你只要做.net開發,你就一定天天在用。因為VS的智慧提示就是透過應用了反射技術來實現的,還有我們常用的反編譯神器Reflector.exe,看它的名字就知道了。專案中比較常見的,是透過結合設定檔來動態實例化對象,如切換資料庫實例,或Sprint.net的透過設定檔來實現依賴注入等。

反射技術其實就是動態取得組件的元資料的功能,反射透過動態載入dll,然後對其進行解析,從而創建對象,呼叫成員。

Type是對類別的描述,Type類別是實現反射的一個重要的類,透過它我們可以取得類別中的所有信息,包括方法、屬性等。可以動態呼叫類別的屬性、方法。

反射的出現讓創建物件的方式發生了改變,因為過去面完創建物件都是直接透過new。

dll裡面有兩個部分東西:IL中間語言和metadate元素據。

在.NET中反射用到命名空間是System.Reflection,這裡我先透過一個Demo來看反射能做些什麼

#1、  新建控制台專案ReflectedDemo

2、  新建類別庫專案My.Sqlserver.Dal

新建兩個類別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、  專案ReflectedDemo,新增My.Sqlserver.Dal的專案引用,我這樣做的目的是為了方便專案ReflectedDemo中的bin目錄中時刻存在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");//获取程序集中指定名称的类型对象
      Console.WriteLine(typeName.Name);
    }
  }
}
登入後複製

動態建立物件

#

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

他们之间的区别

ass.CreateInstance(string typeName) 会动态调用类的无参构造函数创建一个对象,返回值就是创建的对象,如果没有无参构造函数就会报错。


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

如果我们来修改SqlServerHelper类的代码,添加如下构造函数:

    public SqlServerHelper(int age)
    {
      this.age = age;
    }
登入後複製

这个时候再来运行创建实例的代码就会报错了,而编译时是不报错的。

所以我们一般推荐使用Activator.CreateInstance方法来创建反射对象,因为此方法有许多重载,支持将参数传递给构造函数。

此时再调用就不会出现异常了。

Type类中有三个用得比较多的方法:

  • bool IsAssignableFrom(Type t):是否可以从t赋值,判断当前的类型变量是不是可以接受t类型变量的赋值。

  • bool IsInstanceOfType(object o):判断对象o是否是当前类的实例,当前类可以是o的类、父类、接口

  • bool IsSubclassOf(Type t):判断当前类是否是t的子类

Type类中还有一个IsAbstract属性:判断是否为抽象的,包含接口。

它们常用的原因是我们通过反射可以取到的东西太多了,我们需要对数据进行过滤。

添加类BaseSql,让类SqlServerHelper继承自BaseSql

然后查看调用代码:

      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);
登入後複製

项目中常用的利用反射来动态切换数据库Demo:

新建类库项目My.Sql.IDal,并添加接口ISqlHelper。通过接口来实现数据库操作的类的解耦,因为接口是抽象的。

  public interface ISqlHelper
  {
    string Query();
  }
登入後複製

添加类库项目My.MySql.Dal,并新增类MySqlHelper.cs

My.Sqlserver.Dal、My.MySql.Dal项目分别添加对项目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配置项

 <appSettings>
  <add key="DBName" value="My.Sqlserver.Dal,SqlServerHelper"/>
 </appSettings>
登入後複製

ReflectedDemo项目中Program.cs调用代码:

string str = ConfigurationManager.AppSettings["DBName"];
      string strAssembly = str.Split(&#39;,&#39;)[0];
      string strClass=str.Split(&#39;,&#39;)[1];
      Assembly assembly = Assembly.Load(strAssembly);
      Type t = assembly.GetType(strAssembly + "." + strClass);
      ISqlHelper obj = Activator.CreateInstance(t) as ISqlHelper;
      Console.WriteLine(obj.Query());
登入後複製

这样每次需要切换数据库时,只要修改配置文件就可以了。

项目结构:

注意:反射虽然很强大,但却是比较耗性能的,所以一般和缓存结合起来使用。

以上是C#程式集與反射的圖文程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

使用 C# 的活動目錄 使用 C# 的活動目錄 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在這裡,我們討論 Active Directory 在 C# 中的介紹和工作原理以及語法和範例。

C# 序列化 C# 序列化 Sep 03, 2024 pm 03:30 PM

C# 序列化指南。這裡我們分別討論C#序列化物件的介紹、步驟、工作原理和範例。

C# 中的隨機數產生器 C# 中的隨機數產生器 Sep 03, 2024 pm 03:34 PM

C# 隨機數產生器指南。在這裡,我們討論隨機數產生器的工作原理、偽隨機數和安全數的概念。

C# 資料網格視圖 C# 資料網格視圖 Sep 03, 2024 pm 03:32 PM

C# 資料網格視圖指南。在這裡,我們討論如何從 SQL 資料庫或 Excel 檔案載入和匯出資料網格視圖的範例。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在這裡,我們討論 C# 中模式的介紹和前 3 種類型,以及其範例和程式碼實作。

C# 中的質數 C# 中的質數 Sep 03, 2024 pm 03:35 PM

C# 質數指南。這裡我們討論c#中素數的介紹和範例以及程式碼實作。

C# 中的階乘 C# 中的階乘 Sep 03, 2024 pm 03:34 PM

C# 階乘指南。這裡我們討論 C# 中階乘的介紹以及不同的範例和程式碼實作。

c#多線程和異步的區別 c#多線程和異步的區別 Apr 03, 2025 pm 02:57 PM

多線程和異步的區別在於,多線程同時執行多個線程,而異步在不阻塞當前線程的情況下執行操作。多線程用於計算密集型任務,而異步用於用戶交互操作。多線程的優勢是提高計算性能,異步的優勢是不阻塞 UI 線程。選擇多線程還是異步取決於任務性質:計算密集型任務使用多線程,與外部資源交互且需要保持 UI 響應的任務使用異步。

See all articles