Espace de noms et classe avec le même nom?

95

J'organise un projet de bibliothèque et j'ai une classe de gestionnaire central nommée Scenegraphet tout un tas d'autres classes qui vivent dans l'espace de noms Scenegraph.

Ce que j'aimerais vraiment, c'est que le scénegraph soit MyLib.Scenegraphet que les autres classes soient MyLib.Scenegraph.*, mais il semble que la seule façon de le faire serait de créer toutes les autres classes des classes internes du Scenegraphfichier Scenegraph.cs et c'est tout simplement trop lourd .

Au lieu de cela, je l'ai organisé en tant que Mylib.Scenegraph.Scenegraphet MyLib.Scenegraph.*, ce qui fonctionne, mais je trouve que Visual Studio est confus dans certaines conditions quant à savoir si je fais référence à la classe ou à l'espace de noms.

Existe-t-il un bon moyen d'organiser ce package pour qu'il soit pratique pour les utilisateurs sans gâcher tout mon code dans un désordre impossible à maintenir?

user430788
la source

Réponses:

111

Je ne vous recommande pas de nommer une classe comme son espace de noms, voyez ceci .

Les directives de conception de cadre indiquent dans la section 3.4 «n'utilisez pas le même nom pour un espace de noms et un type dans cet espace de noms». C'est:

namespace MyContainers.List 
{ 
    public class List {  } 
}

Pourquoi cette méchanceté? Oh, laissez-moi compter les façons.

Vous pouvez vous mettre dans des situations où vous pensez que vous faites référence à une chose mais que vous faites en fait référence à autre chose. Supposons que vous vous retrouviez dans cette situation malheureuse: vous écrivez Blah.DLL et importez Foo.DLL et Bar.DLL, qui, malheureusement, ont tous deux un type appelé Foo:

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah  
{   
using Foo;   
using Bar;   
class C { Foo foo; } 
}

Le compilateur donne une erreur. «Foo» est ambigu entre Foo.Foo et Bar.Foo. Dommage. Je suppose que je vais résoudre ce problème en qualifiant complètement le nom:

   class C { Foo.Foo foo; } 

Cela donne maintenant l'erreur d'ambiguïté « Foo dans Foo.Foo est ambigu entre Foo.Foo et Bar.Foo ». Nous ne savons toujours pas à quoi fait référence le premier Foo, et jusqu'à ce que nous puissions le comprendre, nous ne prenons même pas la peine d'essayer de comprendre à quoi le second fait référence.

pinckerman
la source
6
C'est un point intéressant. Im encore lcogiting là-dessus. Merci. Je dois être honnête avec des arguments qui commencent par "Le guide de style dit" ne m'impressionne pas. J'ai vu énormément de conneries injustifiées dans les guides de style. Mais vous faites un bon argument pratique ci-dessus. Cela vaut la peine d'y penser, de toute façon.
user430788
5
La réponse dit "ce qu'il ne faut pas faire". Alors que certains utilisateurs de la pile recherchent "quoi faire". Quelqu'un recommanderait-il la réponse Ant_222?
fantaisie
3
Si vous êtes vraiment bloqué, vous pouvez toujours créer un alias de type en dehors de votre espace de noms. Les alias externes ne sont nécessaires que lorsque vous avez deux identificateurs complets complètement identiques (espace de nom + nom de classe).
Geoffrey
4
Tout ce qui précède est au revoir et à l'opinion. Le fait est que vous ne devriez pas le faire parce que le compilateur C # le comprendra mal , bien qu'on lui dise assez clairement ce qui se passe. Par exemple, using Foo.Bar;alors plus tard Bar bfait clairement référence à Barune classe (ou une énumération) à l'intérieur de l'espace de noms Foo.Bar. La vraie raison de ne pas faire cela est purement que le compilateur C # ne le comprend pas correctement, ce qui est terriblement surprenant et malheureux. Tout le reste est un conseil de style laineux.
TJ Crowder
2
Je ne comprends pas. Pourquoi Foo.Foo est-il ambigu? Vous dites directement au compilateur que vous souhaitez utiliser la classe Foo de l'espace de noms Foo dans ce cas précis. Non?
GuardianX
14

Donner le même nom à l'espace de noms et à la classe peut dérouter le compilateur comme d'autres l'ont dit.

Comment le nommer alors?

Si l'espace de noms a plusieurs classes, recherchez un nom qui définit toutes ces classes.

Si l' espace de noms n'a qu'une seule classe (et donc la tentation de lui donner le même nom), nommez l'espace de noms ClassName NS . C'est ainsi que Microsoft nomme au moins leurs espaces de noms.

Aller à
la source
4
Avez-vous un exemple d'un tel espace de noms de Microsoft?
sunefred
Je dois le rechercher et revenir vers vous.
GoTo
@sunefred Je l'ai cherché, mais je ne l'ai pas trouvé. Mais je me souviens vraiment de l'avoir vu dans la documentation. Je suppose qu'il n'y a pas beaucoup de cas où vous souhaitez avoir une seule classe dans un espace de noms.
GoTo
9

Je vous suggère de suivre les conseils que j'ai reçus microsoft.public.dotnet.languages.csharppour utiliser MyLib.ScenegraphUtil.Scenegraphet MyLib.ScenegraphUtil.*.

Ant_222
la source
7

CA1724: Type Names Should Not Match Namespaces ...

Fondamentalement, si vous suivez l'analyse du code pour un codage approprié, cette règle dit de ne pas faire ce que vous essayez de faire. L'analyse de code est très utile pour vous aider à trouver des problèmes potentiels .

myermien
la source
4

Juste ajouter mes 2 cents:

J'ai eu le cours suivant:

namespace Foo {
    public struct Bar {
    }
    public class Foo {
        //no method or member named "Bar"
    }
}

Le client a été écrit comme ceci:

using Foo;

public class Blah {
    public void GetFoo( out Foo.Bar[] barArray ) {
    }
}

Oubliant l'erreur GetFoo de ne pas renvoyer la sortie au lieu d'utiliser le paramètre out, le compilateur n'a pas pu résoudre le type de données Foo.Bar []. Il renvoyait l'erreur: impossible de trouver le type ou l'espace de noms Foo.Bar.

Il semble que lorsqu'il essaie de compiler, il a résolu Foo en tant que classe et n'a pas trouvé de classe intégrée Bar dans la classe Foo. Il n'a pas non plus pu trouver un espace de noms appelé Foo.Bar. Il n'a pas réussi à rechercher une classe Bar dans l'espace de noms Foo. Les points dans un espace de nom ne sont PAS syntaxiques. La chaîne entière est un jeton, pas les mots délimités par les points.

Ce comportement a été présenté par VS 2015 exécutant .Net 4.6

Steve
la source
4

Même si je suis d'accord avec d'autres réponses, vous ne devez pas nommer votre classe de la même manière que votre espace de noms il y a des moments où vous ne pouvez pas vous conformer à ces exigences.

Dans mon cas, par exemple, je n'étais pas la personne qui prenait une telle décision, donc je devais trouver un moyen de la faire fonctionner.

Donc, pour ceux qui ne peuvent pas changer le nom de l'espace de noms ni le nom de la classe, voici un moyen de faire fonctionner votre code.

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah
{
    using FooNSAlias = Foo;//alias
    using BarNSAlias = Bar;//alias
    class C { FooNSAlias.Foo foo; }//use alias to fully qualify class name
}

Fondamentalement, j'ai créé des "alias" d'espace de noms et cela m'a permis de qualifier complètement la classe et la "confusion" de Visual Studio a disparu.

REMARQUE: vous devez éviter ce conflit de dénomination s'il est sous votre contrôle pour ce faire. Vous ne devez utiliser la technique mentionnée que lorsque vous ne contrôlez pas les classes et les espaces de noms en question.

Jonathan Alfaro
la source
2
Je l'ai voté parce que c'était une solution intéressante à un monde imparfait.
user430788
2

Ancien message, mais ici je vais avec une autre idée qui peut aider quelqu'un:

"... mais il semble que le seul moyen de le faire serait de créer toutes les autres classes des classes internes de Scenegraph dans le fichier Scenegraph.cs et c'est trop compliqué."

C'est vraiment la meilleure implémentation pour un tas de scénarios. Mais je suis d'accord pour dire qu'avoir tout ce code sur le même fichier .cs est ennuyeux (c'est le moins qu'on puisse dire).

Vous pouvez le résoudre en faisant de la classe de base une "classe partielle" et ensuite, continuer à créer les classes internes sur leurs propres fichiers (rappelez-vous simplement qu'ils devront déclarer le complément de classe de base, puis continuer avec la classe interne spécifique pour ce fichier).

Quelque chose comme...

Scenegraph.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        //Scenegraph specific implementations
    }
}

DependentClass.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        public class DependentClass
        {
            //DependentClass specific implementations
        }
    }
}

Je pense que c'est le plus proche que vous pouvez obtenir de l'implémentation propre des classes internes sans avoir à tout encombrer dans un fichier énorme et désordonné.

Marcelo Myara
la source
2

Comme d'autres l'ont dit, c'est une bonne pratique d'éviter de nommer une classe de la même manière que son espace de noms.

Voici quelques suggestions de dénomination supplémentaires à partir d' une réponse de svick à une question connexe «Même nom de classe et d'espace de noms» sur la plateforme Software Engineering Stack Exchange:

Vous avez raison de ne pas nommer l'espace de noms de la même manière qu'un type qu'il contient. Je pense qu'il existe plusieurs approches que vous pouvez utiliser:

  • Pluraliser: Model.DataSources.DataSource

Cela fonctionne particulièrement bien si l'objectif principal de l'espace de noms est de contenir des types qui héritent du même type de base ou d'implémenter la même interface.

  • Raccourcir: Model.QueryStorage

Si un espace de noms ne contient qu'un petit nombre de types, vous n'avez peut-être pas du tout besoin de cet espace de noms.

  • Créez une entreprise: Model.ProjectSystem.Project

Cela peut fonctionner en particulier pour les fonctionnalités qui sont une partie importante de votre produit, elles méritent donc leur propre nom.

(Notez que les utilisations de réponse ci - dessus Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.et Model.Project.Projectcomme exemples plutôt que MyLib.Scenegraph.Scenegraph.)

(J'ai également trouvé les autres suggestions de noms dans les autres réponses ici utiles.)

fiston
la source
1

Cela se produit quand c'est la classe principale de l'espace de noms. C'est donc une motivation pour mettre l'espace de noms dans une bibliothèque, puis le problème disparaît si vous ajoutez 'Lib' au nom de l'espace de noms ...

namespace SocketLib
{
    class Socket
    {
Paul Sumpner
la source