程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 順序集和反射(C#)

順序集和反射(C#)

編輯:C#入門知識

順序集和反射(C#)。本站提示廣大學習愛好者:(順序集和反射(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(',')[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());

這樣每次需求切換數據庫時,只需修正配置文件就可以了。

項目構造:

留意:反射雖然很弱小,但卻是比擬耗功能的,所以普通弛緩存結合起來運用。

項目源碼:ReflectedDemo.zip

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved