本文主要介紹了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());
这样每次需要切换数据库时,只要修改配置文件就可以了。
项目结构:
注意:反射虽然很强大,但却是比较耗性能的,所以一般和缓存结合起来使用。
以上是C#程式集與反射的圖文程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

如何使用C#编写时间序列预测算法时间序列预测是一种通过分析过去的数据来预测未来数据趋势的方法。它在很多领域,如金融、销售和天气预报中有广泛的应用。在本文中,我们将介绍如何使用C#编写时间序列预测算法,并附上具体的代码示例。数据准备在进行时间序列预测之前,首先需要准备好数据。一般来说,时间序列数据应该具有足够的长度,并且是按照时间顺序排列的。你可以从数据库或者

如何使用Redis和C#开发分布式事务功能引言分布式系统的开发中,事务处理是一项非常重要的功能。事务处理能够保证在分布式系统中的一系列操作要么全部成功,要么全部回滚。Redis是一种高性能的键值存储数据库,而C#是一种广泛应用于开发分布式系统的编程语言。本文将介绍如何使用Redis和C#来实现分布式事务功能,并提供具体代码示例。I.Redis事务Redis

如何实现C#中的人脸识别算法人脸识别算法是计算机视觉领域中的一个重要研究方向,它可以用于识别和验证人脸,广泛应用于安全监控、人脸支付、人脸解锁等领域。在本文中,我们将介绍如何使用C#来实现人脸识别算法,并提供具体的代码示例。实现人脸识别算法的第一步是获取图像数据。在C#中,我们可以使用EmguCV库(OpenCV的C#封装)来处理图像。首先,我们需要在项目

Redis在C#开发中的应用:如何实现高效的缓存更新引言:在Web开发中,缓存是提高系统性能的常用手段之一。而Redis作为一款高性能的Key-Value存储系统,能够提供快速的缓存操作,为我们的应用带来了不少便利。本文将介绍如何在C#开发中使用Redis,实现高效的缓存更新。Redis的安装与配置在开始之前,我们需要先安装Redis并进行相应的配置。你可以

如何使用C#编写动态规划算法摘要:动态规划是求解最优化问题的一种常用算法,适用于多种场景。本文将介绍如何使用C#编写动态规划算法,并提供具体的代码示例。一、什么是动态规划算法动态规划(DynamicProgramming,简称DP)是一种用来求解具有重叠子问题和最优子结构性质的问题的算法思想。动态规划将问题分解成若干个子问题来求解,通过记录每个子问题的解,

如何实现C#中的图像压缩算法摘要:图像压缩是图像处理领域中的一个重要研究方向,本文将介绍在C#中实现图像压缩的算法,并给出相应的代码示例。引言:随着数字图像的广泛应用,图像压缩成为了图像处理中的重要环节。压缩能够减小存储空间和传输带宽,并能提高图像处理的效率。在C#语言中,我们可以通过使用各种图像压缩算法来实现对图像的压缩。本文将介绍两种常见的图像压缩算法:

C#开发中如何处理跨域请求和安全性问题在现代的网络应用开发中,跨域请求和安全性问题是开发人员经常面临的挑战。为了提供更好的用户体验和功能,应用程序经常需要与其他域或服务器进行交互。然而,浏览器的同源策略导致了这些跨域请求被阻止,因此需要采取一些措施来处理跨域请求。同时,为了保证数据的安全性,开发人员还需要考虑一些安全性问题。本文将探讨C#开发中如何处理跨域请

如何在C#中实现遗传算法引言:遗传算法是一种模拟自然选择和基因遗传机制的优化算法,其主要思想是通过模拟生物进化的过程来搜索最优解。在计算机科学领域,遗传算法被广泛应用于优化问题的解决,例如机器学习、参数优化、组合优化等。本文将介绍如何在C#中实现遗传算法,并提供具体的代码示例。一、遗传算法的基本原理遗传算法通过使用编码表示解空间中的候选解,并利用选择、交叉和


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

Dreamweaver Mac版
視覺化網頁開發工具

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

記事本++7.3.1
好用且免費的程式碼編輯器