Maison  >  Article  >  développement back-end  >  Explication détaillée du code graphique de l'assemblage et de la réflexion C#

Explication détaillée du code graphique de l'assemblage et de la réflexion C#

黄舟
黄舟original
2017-03-29 11:45:381881parcourir

Cet article présente principalement les connaissances sur l'assemblage et la réflexion C#. Il a une certaine valeur de référence, jetons-y un coup d'œil avec l'éditeur ci-dessous

Ici, je dirai quelques mots supplémentaires. Tout le monde se sent très heureux lorsqu'il étudie, comme lire des livres ou regarder des vidéos, car. en gros, ils ont envie de regarder. C'est assez facile à comprendre. En fait, c'est une chose de pouvoir le faire soi-même, c'en est une autre de pouvoir le parler soi-même. Vous devriez vous approprier ce que vous apprenez, plutôt que de copier les autres.

Avant de parler de réflexion, comprenons d’abord ce qu’est une assemblée ?

Assembly

Assembly est un concept dans .net. Un assembly peut être considéré comme un package pour un ensemble de classes associées, ce qui équivaut à jar en Java. Sac.

Les assemblages contiennent :

  • Fichiers de ressources

  • Métadonnées de type (décrivant chaque type et membres, sous forme binaire)

  • Code IL (ceux-ci sont encapsulés dans exe ou dll)

La différence entre exe et dll.

exe peut s'exécuter, mais dll ne peut pas s'exécuter directement, car il y a une mainfonction (fonction d'entrée) dans exe.

Tapez les métadonnées Ces informations peuvent être personnalisées via le fichier AssemblyInfo.cs. Il existe un fichier AssemblyInfo.cs dans chaque projet .net. Le format du code est :

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")]

Où ces informations sont-elles reflétées ? Cela se reflète dans les propriétés de notre assembly

Lorsque nous installons habituellement certains programmes clients CS, nous en verrons beaucoup sous le fichier d'assembly du répertoire d'installation.

Avantages de l'utilisation d'assemblys

  • Seuls les assemblys nécessaires sont référencés dans le programme, réduisant ainsi la taille du programme.

  • Les assemblys peuvent encapsuler du code et fournir uniquement les interfaces d'accès nécessaires.

  • Facile à développer.

Comment ajouter une référence à un assembly ?

Ajoutez directement le chemin d'assemblage ou ajoutez une référence de projet dans la solution.

Lorsque nous avons besoin d'étendre un programme, vous pouvez l'ajouter directement au projet original. Dans ce cas, que se passe-t-il si vous souhaitez partager votre code avec d'autres ? Vous pouvez le regrouper dans un assembly, puis d’autres personnes peuvent l’étendre en référençant votre assembly. Comme nos bibliothèques framework tierces .net communes, telles que log4net, unity, etc.

Remarque : Vous ne pouvez pas ajouter une référence circulaire

Qu'est-ce que l'ajout d'une référence circulaire ? C'est-à-dire que si le projet A ajoute une référence de projet au projet B, alors le projet B ne peut pas ajouter de référence de projet au projet A pour le moment. C'est-à-dire que lors de l'ajout d'une référence de projet, cela doit être à sens unique, par exemple. notre cadre commun à trois niveaux de références de projets.

Réflexion

Quant à la réflexion, tant que vous faites du développement .net, vous l'utiliserez certainement tous les jours. Étant donné que les invites intelligentes de VS sont réalisées en appliquant la technologie de réflexion, ainsi que notre artefact de décompilation couramment utilisé Reflector.exe, il suffit de regarder son nom. Il est plus courant dans les projets d'instancier dynamiquement des objets en combinant des fichiers de configuration, tels que le changement d'instance de base de données ou l'injection de dépendances de Sprint.net via des fichiers de configuration.

La technologie Reflection a en fait pour fonction d'obtenir dynamiquement les métadonnées d'un assembly. Reflection charge dynamiquement la DLL puis l'analyse pour créer des objets et appeler des membres.

Type est une description de la classe. La classe Type est une classe importante pour implémenter la réflexion. Grâce à elle, nous pouvons obtenir toutes les informations de la classe, y compris les méthodes, les attributs, etc. Les propriétés et méthodes des classes peuvent être appelées dynamiquement.

L'émergence de la réflexion a changé la manière de créer des objets, car dans le passé, les objets étaient créés directement à travers le nouveau.

Il y a deux parties dans la DLL : le langage intermédiaire IL et les données des éléments de métadate.

Le espace de noms utilisé pour la réflexion dans .NET est System.Reflection. Ici, je vais d'abord utiliser une démo pour voir ce que la réflexion peut faire

1. Project ReflectedDemo

2. Créez une nouvelle bibliothèque de classes projet My.Sqlserver.Dal

Créez deux nouvelles classes, SqlServerHelper et SqlCmd, la première est une classe publique et la cette dernière est une classe privée

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. Project ReflectedDemo, ajoutez la référence du projet My.Sqlserver.Dal Le but de ceci est de faciliter l'existence de l'assembly My.Sqlserver.Dal.dll dans. le répertoire bin dans le projet ReflectedDemo.

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);
    }
  }
}

Créer dynamiquement des objets

通过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());

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

项目结构:

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn