web-dev-qa-db-fra.com

Utilisations pratiques du mot clé "interne" en C #

Pourriez-vous s'il vous plaît expliquer quelle est l'utilisation pratique du mot clé internal en C #?

Je sais que le modificateur internal limite l'accès à l'Assemblée actuelle, mais quand et dans quelles circonstances dois-je l'utiliser?

394

Classes/méthodes utilitaires ou auxiliaires auxquelles vous souhaitez accéder à partir de nombreuses autres classes du même assemblage, mais que vous souhaitez vous assurer que le code des autres assemblys ne peut pas y accéder.

De MSDN (via archive.org):

Une utilisation courante de l'accès interne est le développement à base de composants, car elle permet à un groupe de composants de coopérer de manière privée sans être exposés au reste du code de l'application. Par exemple, un cadre permettant de créer des interfaces utilisateur graphiques pourrait fournir des classes de contrôle et de formulaire coopérant à l'aide de membres disposant d'un accès interne. Étant donné que ces membres sont internes, ils ne sont pas exposés au code utilisant le cadre.

Vous pouvez également utiliser le modificateur internal en même temps que InternalsVisibleTo Attribut de niveau d'assemblage pour créer des assemblys "amis" dotés d'un accès spécial aux classes internes de l'assembly cible.

Cela peut être utile pour créer des assemblys de test unitaire qui sont ensuite autorisés à appeler des membres internes de l'assemblage à tester. Bien entendu, aucun autre assemblage ne dispose de ce niveau d'accès. Par conséquent, lorsque vous libérez votre système, l'encapsulation est conservée.

353
Ash

Si Bob a besoin de BigImportantClass, il doit faire en sorte que les détenteurs du projet A s’inscrivent pour garantir que BigImportantClass sera écrit pour répondre à ses besoins, testé pour s’assurer qu’il répond à ses besoins, est documenté comme répondant à ses besoins et qu’un processus sera mis en place pour s'assurer qu'il ne sera jamais changé afin de ne plus répondre à ses besoins.

Si une classe est interne, elle n’a pas à passer par ce processus, ce qui économise un budget pour le projet A qu’elle peut consacrer à autre chose.

Le problème d’interne n’est pas que cela rend la vie difficile à Bob. Cela vous permet de contrôler les promesses coûteuses que le projet A fait concernant les fonctionnalités, la durée de vie, la compatibilité, etc.

82
Eric Lippert

Une autre raison d'utiliser interne est que vous obscurcissez vos fichiers binaires. L'obfuscateur sait qu'il est prudent de brouiller le nom de classe de toute classe interne, alors que le nom de classe publique ne peut pas être brouillé, car cela pourrait casser les références existantes.

57
Joel Mueller

Si vous écrivez une DLL qui encapsule une tonne de fonctionnalités complexes dans une simple API publique, alors "interne" est utilisé pour les membres de la classe qui ne doivent pas être exposés publiquement.

Cacher la complexité (encapsulation, etc.) est le concept principal du génie logiciel de qualité.

27

Le mot clé internal est fortement utilisé lorsque vous créez un wrapper sur du code non géré.

Lorsque vous avez une bibliothèque basée sur C/C++ que vous souhaitez importer avec DllImport, vous pouvez importer ces fonctions en tant que fonctions statiques d'une classe et les rendre internes, afin que votre utilisateur n'ait accès qu'à votre enveloppe et non à l'API d'origine. gâcher avec n'importe quoi. Les fonctions étant statiques, vous pouvez les utiliser partout dans l’Assembly, pour les multiples classes de wrapper dont vous avez besoin.

Vous pouvez jeter un oeil à Mono.Cairo, c'est une enveloppe autour de la bibliothèque du Caire qui utilise cette approche.

20
Edwin Jarvis

Étant conduit par "utiliser comme modificateur strict autant que vous le pouvez", j'utilise internal partout où j'ai besoin d'accéder, par exemple, à une méthode d'une autre classe jusqu'à ce que je devrais explicitement y accéder depuis un autre assembly.

Comme l'interface d'assemblage est généralement plus étroite que la somme de ses interfaces de classes, il y a beaucoup d'endroits où je l'utilise.

12
Ilya Komakhin

Je trouve interne à être beaucoup trop utilisé. vous ne devriez vraiment pas exposer certaines fonctions à certaines catégories de personnes, mais pas à d’autres consommateurs.

Ceci à mon avis casse l'interface, casse l'abstraction. Cela ne veut pas dire qu'il ne devrait jamais être utilisé, mais une meilleure solution consiste à refactoriser une classe différente ou à l'utiliser de manière différente, si possible. Cependant, cela peut ne pas être toujours possible.

Cela peut être dû au fait qu'un autre développeur peut être chargé de créer une autre classe dans le même assemblage que le vôtre. Avoir des internes amoindrit la clarté de l'abstraction et peut causer des problèmes s'il est mal utilisé. Ce serait le même problème que si vous le rendiez public. L'autre classe en cours de construction par l'autre développeur reste un consommateur, comme toute classe externe. L'abstraction et l'encapsulation de classes ne servent pas uniquement à la protection des classes externes, mais à toutes les classes.

Un autre problème est que beaucoup de développeurs vont penser ils auront peut-être besoin de l’utiliser ailleurs dans l’Assemblée et de le marquer comme interne, même s’ils n’en ont pas besoin à ce moment-là. Un autre développeur peut alors penser que c'est là pour la prise. Généralement, vous souhaitez marquer privé jusqu'à ce que vous ayez un besoin impératif.

Mais certaines de ces choses peuvent être subjectives, et je ne dis pas que cela ne devrait jamais être utilisé. Il suffit d'utiliser quand nécessaire.

10
mattlant

J’en ai vu un intéressant, peut-être une semaine, sur un blog dont je ne me souviens plus. En gros, je ne peux pas en accepter le mérite, mais je pensais que cela pourrait avoir une application utile.

Supposons que vous vouliez qu'une classe abstraite soit vue par une autre assemblée, mais que vous ne vouliez pas que quelqu'un puisse en hériter. Sealed ne fonctionnera pas car c'est abstrait pour une raison, les autres classes de cette Assemblée en héritent. Private ne fonctionnera pas car vous voudrez peut-être déclarer une classe Parent quelque part dans l'autre Assembly.

 namespace Base.Assembly 
 {
 classe abstraite publique Parent 
 {
 interne abstraite void SomeMethod (); 
} 
 
 // Cela fonctionne très bien puisqu'il se trouve dans la même Assemblée. 
, Classe publique ChildWithin: Parent 
 {
, Remplacement interne void SomeMethod () 
 {
} 
} 
} 
 
 Un autre.Assemblée 
 {
 // Kaboom , car vous ne pouvez pas remplacer une méthode interne 
, classe publique ChildOutside: Parent 
 {
} 
 
 test de classe publique 
 {
 
 // Très bien 
 Parent privé _parent; 
 
 Test public () 
 {
// Toujours correct 
 _Parent = new ChildWithin (); 
} 
} 
} 

Comme vous pouvez le constater, cela permet effectivement à quelqu'un d'utiliser la classe Parent sans pouvoir en hériter.

8
Programmin Tool

Cet exemple contient deux fichiers: Assembly1.cs et Assembly2.cs. Le premier fichier contient une classe de base interne, BaseClass. Dans le second fichier, une tentative d'instanciation de BaseClass générera une erreur.

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

Dans cet exemple, utilisez les mêmes fichiers que dans l'exemple 1 et modifiez le niveau d'accessibilité de BaseClass en public . Modifiez également le niveau d'accessibilité du membre IntM en internal . Dans ce cas, vous pouvez instancier la classe, mais vous ne pouvez pas accéder au membre interne.

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

source : http://msdn.Microsoft.com/en-us/library/7c5ka91b (VS.80) .aspx =

7
Murad Mohd Zain

Une utilisation très intéressante d’internal - les membres internes étant bien entendu limités à l’Assemblée dans laquelle elle est déclarée - consiste à utiliser la fonctionnalité "ami" dans une certaine mesure. Un membre ami est quelque chose qui n'est visible que par certaines autres assemblées en dehors de l'Assemblée dans laquelle il est déclaré. C # n'a pas de support intégré pour un ami, contrairement au CLR.

Vous pouvez utiliser InternalsVisibleToAttribute pour déclarer une assemblée amie, et toutes les références provenant de cette assemblée traiteront les membres internes de votre assemblée déclarante comme publics dans le cadre de cette assemblée. Un problème avec ceci est que tous les membres internes sont visibles; vous ne pouvez pas choisir et choisir.

InternalsVisibleTo peut être utilisé à bon escient pour exposer divers membres internes à un assemblage de test unitaire, éliminant ainsi le besoin de réflexions complexes pour tester ces membres. Le fait que tous les membres internes soient visibles ne pose pas vraiment de problème. Cependant, cette approche gâche lourdement les interfaces de votre classe et peut potentiellement ruiner l’encapsulation au sein de l’Assemblée déclarante.

6
cfeduke

Lorsque vous avez des méthodes, des classes, etc. qui doivent être accessibles dans le cadre de l’Assemblée actuelle et jamais en dehors de celle-ci.

Par exemple, un DAL peut avoir un ORM, mais les objets ne doivent pas être exposés à la couche de gestion. Toutes les interactions doivent être effectuées via des méthodes statiques et en passant les paramètres requis.

5
Aaron Powell

En règle générale, il existe deux types de membres:

  • surface publique: visible depuis un assembly externe (public, protégé et interne protégé): l'appelant n'est pas approuvé. Par conséquent, la validation des paramètres, la documentation de la méthode, etc. sont nécessaires.
  • surface privée: non visible d'un assemblage externe (classes privées et internes ou internes): l'appelant est généralement approuvé. La validation des paramètres, la documentation de la méthode, etc. peuvent donc être omis.
5
Michael Damatov

Les classes internes vous permettent de limiter l'API de votre assembly. Cela présente des avantages, tels que la simplification de la compréhension de votre API.

De plus, si un bogue existe dans votre assemblage, il est moins probable que le correctif introduit un changement radical. Sans classes internes, vous devriez supposer que changer les membres du public d'une classe serait un changement décisif. Avec les classes internes, vous pouvez supposer que la modification de leurs membres publics rompt uniquement l'API interne de Assembly (et tous les assemblys référencés dans l'attribut InternalsVisibleTo).

J'aime avoir l'encapsulation au niveau de la classe et au niveau de l'assemblée. Certains sont en désaccord avec cela, mais il est bon de savoir que la fonctionnalité est disponible.

4
xofz

Réduction du bruit, moins vous exposez de types, plus votre bibliothèque est simple. L'inviolabilité/la sécurité en est un autre (bien que Reflection puisse gagner contre elle).

4
Quibblesome

J'ai un projet qui utilise LINQ-to-SQL pour le back-end de données. J'ai deux espaces de noms principaux: Biz et Data. Le modèle de données LINQ vit dans Données et est marqué "interne"; L'espace de noms Biz contient des classes publiques qui entourent les classes de données LINQ.

Donc, il y a Data.Client et Biz.Client; ce dernier expose toutes les propriétés pertinentes de l’objet de données, par exemple:

private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }

Les objets Biz ont un constructeur privé (pour forcer l'utilisation de méthodes d'usine) et un constructeur interne qui ressemble à ceci:

internal Client(Data.Client client) {
    this._client = client;
}

Cela peut être utilisé par toutes les classes métiers de la bibliothèque, mais l'interface frontale (interface utilisateur) n'a aucun moyen d'accéder directement au modèle de données, garantissant ainsi que la couche métier agit toujours comme un intermédiaire.

C’est la première fois que j’utilise beaucoup internal et cela s’avère très utile.

2
Keith Williams

Il y a des cas où il est logique de faire des membres de classes internal. Un exemple pourrait être si vous souhaitez contrôler la manière dont les classes sont instanciées; Supposons que vous fournissiez une sorte d’usine pour créer des instances de la classe. Vous pouvez créer le constructeur internal, de sorte que la fabrique (qui réside dans le même assembly) puisse créer des instances de la classe, mais pas le code situé en dehors de cet assembly.

Cependant, je ne vois aucun intérêt à créer des classes ou des membres internal sans raisons spécifiques, aussi peu qu'il soit logique de les rendre public ou private sans raisons spécifiques.

2
Fredrik Mörk

la seule chose sur laquelle j'ai déjà utilisé le mot-clé internal est le code de vérification de licence dans mon produit ;-)

1
Steven A. Lowe

Une utilisation du mot-clé internal est de limiter l'accès à des implémentations concrètes de l'utilisateur de votre assembly.

Si vous avez une usine ou un autre emplacement central pour la construction d'objets, l'utilisateur de votre assembly n'a besoin que de traiter avec l'interface publique ou la classe de base abstraite.

De plus, les constructeurs internes vous permettent de contrôler où et quand une classe publique est instanciée.

1
Andrew Kennan

Gardez à l'esprit que toute classe définie comme public apparaîtra automatiquement dans l'intellisense lorsque quelqu'un regardera l'espace de noms de votre projet. Du point de vue de l'API, il est important de ne montrer qu'aux utilisateurs de votre projet les classes qu'ils peuvent utiliser. Utilisez le mot clé internal pour masquer les éléments qu’ils ne devraient pas voir.

Si votre Big_Important_Class pour le projet A est destiné à être utilisé en dehors de votre projet, vous ne devez pas le marquer internal.

Cependant, dans de nombreux projets, vous aurez souvent des classes destinées à être utilisées uniquement dans un projet. Par exemple, vous pouvez avoir une classe qui contient les arguments d'une invocation de thread paramétrée. Dans ces cas, vous devez les marquer comme suit: internal si vous ne vous protégez que pour vous protéger des modifications inattendues de l'API.

1
Matt Davis

Que diriez-vous de celui-ci: en règle générale, il est recommandé de ne pas exposer un objet de liste à des utilisateurs externes d'un assembly, mais d'exposer un IEnumerable. Mais il est beaucoup plus facile d’utiliser un objet List dans l’Assembly, car vous obtenez la syntaxe du tableau et toutes les autres méthodes List. Donc, j'ai généralement une propriété interne exposant une liste à utiliser dans l'Assemblée.

Les commentaires sur cette approche sont les bienvenus.

1
Samik R

L'idée est que, lorsque vous concevez une bibliothèque, seules les classes destinées à être utilisées de l'extérieur (par les clients de votre bibliothèque) doivent être publiques. De cette façon, vous pouvez masquer les classes qui

  1. Sont susceptibles de changer dans les prochaines versions (si elles étaient publiques, vous casseriez le code client)
  2. Sont inutiles pour le client et peuvent créer de la confusion
  3. Ne sont pas sûrs (une utilisation non conforme risque donc de casser votre bibliothèque)

etc.

Si vous développez des solutions internes, utiliser des éléments internes n’est pas si important que cela, car les clients resteront en contact permanent avec vous et/ou auront accès au code. Ils sont cependant assez critiques pour les développeurs de bibliothèques.

0
Grzenio