web-dev-qa-db-fra.com

'CompanyName.Foo' est un 'espace de noms' mais est utilisé comme un 'type'

Restatement de la question

Je ressuscite cette question parce que je viens encore de rencontrer cette erreur aujourd'hui et je ne comprends toujours pas pourquoi le compilateur C # dérange de vérifier les collisions entre les espaces de noms et les types dans des contextes où l'existence d'un espace de noms n'a aucun sens.

Si j'ai...

public Foo MyFoo { get; set; }

... pourquoi le compilateur se soucierait-il que Foo est à la fois un espace de noms et un type? Pouvez-vous déclarer une propriété comme un espace de noms au lieu d'un type?

Quelle est la logique derrière l'erreur de compilateur "Namespace used like type"? De quel problème est ce qui me sauve?

[Et comment puis-je taguer Eric Lippert? :)]


Question originale


Le problème

J'ai un projet "Foo" avec l'espace de noms par défaut CompanyName.Foo. J'ai une base de données qui s'appelle également "Foo".

Et lorsque j'exécute SqlMetal.exe sur la base de données, il génère une classe CompanyName.Foo.Models.Foo.

Ensuite, lorsque je tente de créer une propriété avec cette classe comme type, comme ceci ...

using CompanyName.Foo.Models;
...
public Foo DataContext { get; set; }

... je reçois l'erreur: 

'CompanyName.Foo' est un 'espace de noms' mais est utilisé comme un 'type'.

Je suis obligé de faire ...

public CompanyName.Foo.Models.Foo Foo { get; set; } // :-(

Des questions:

  1. Pourquoi cette erreur se produit? Ma déclaration de propriété ne contient pas CompanyName, alors pourquoi est-ce un problème? Dit simplement: Foo != CompanyName.Foo. De plus, juste pour être sûr, j'ai fait une recherche de toute ma solution pour namespace Foo et je n'ai obtenu aucun résultat (si j'avais réellement utilisé un espace de noms Foo, je pourrais comprendre avoir une erreur).

  2. [répondu] Existe-t-il un moyen de qualifier entièrement Foo qualifiant chaque fois que je veux l'utiliser?

  3. [réponse] Existe-t-il un moyen d'obtenir que SqlMetal nomme la classe autrement que Foo (sans changer le nom de ma base de données)? Je peux modifier l'espace de noms à l'aide d'un commutateur, mais je ne connais pas de moyen de changer le nom de la classe.

Mettre à jour

Je cherche toujours une réponse à (1).

O.K.W. cloué (2) et (3).

Usings

Une demande a été faite pour toutes mes déclarations using:

using System;
using System.ComponentModel;
using System.Data.Linq;
using System.Linq;
using MyCompany.Foo.Models;
43
devuxer
  1. Le conflit se situe entre namespace CompanyName.Foo et CompanyName.Foo.Models.Foo et non pas Foo. Je ne suis pas tout à fait sûr de savoir comment/pourquoi le compilateur ne peut pas distinguer les deux.

  2. Vous pouvez essayer d’utiliser namespace alias pour raccourcir la qualification complète Foo
    par exemple. using coyModels = CompanyName.Foo.Models

  3. Depuis reference , il semble que vous pouvez utiliser /context:<type> et /namespace:<name> pour spécifier la classe de contexte de données (au lieu d'utiliser le nom de table) et l'espace de nom.

11
o.k.w

Le compilateur C # ne compile pas lorsqu'il existe une ambiguïté entre une classe et un espace de noms portant le même nom. Malheureusement, il vous suffit de nommer explicitement la classe ou de renommer la base de données. Dans votre cas, le compilateur n'a même pas eu connaissance du conflit, il est mort après la résolution de Foo en tant qu'espace de nom.

Chaque fois que vous avez quelque chose comme ça:

using CompanyName.Foo.Models;

namespace CompanyName.Foo {
    class Test {
        public Foo Model { get; set; } // error CS0118: 'CompanyName.Foo' is a 'namespace' but is used like a 'type'
        public Foo1 Model { get; set; } //OK
    }
}

namespace CompanyName.Foo.Models {
    class Foo1 {
    }
    class Foo {
    }
}

En réalité, chaque niveau précédent de l’espace de nom est importé implicitement à chaque niveau. Cela a du sens puisque la syntaxe d’espace de noms imbriquée utilisant dot est la même que celle d’espaces de noms imbriqués:

namespace CompanyName {
    using CompanyName; //<--using1 - Implicit using, since we should be able to access anything within CompanyName implicitly.
    namespace Foo {
        using CompanyName.Foo; //<-- using2 Same as above
        class Test {
            public Foo Model { get; set; } //At this stage due to using1 Foo is actually CompanyName.Foo, hence the compiler error
        }
    }
}

Donc, dans la classe Test, il y a deux usings implicites:

using CompanyName;
using CompanyName.Foo;

Donc Foo est résolu en espace de noms d'où l'erreur.

EDIT Bon point. Je l'ai extrait de _ MSDN :

La signification d'un nom d'espace-ou-type est déterminée comme suit: 

  • Si le nom de l'espace de nom ou du type est constitué d'un identifiant unique:

    • Si l'espace-noms ou le nom-type apparaît dans le corps d'une classe ou d'une structure déclaration, en partant de là déclaration de classe ou de structure et continuer avec chaque classe de clôture ou une déclaration de structure (le cas échéant), s'il s'agit d'un fichier le membre dont le nom existe existe, est accessible, et dénote un type, alors le namespace-or-type-name fait référence à ce membre. Notez que non-type les membres (constantes, champs, méthodes, propriétés , indexeurs, opérateurs, constructeurs d'instance , destructeurs, constructeurs .__ et statiques) sont ignorés lors de la détermination de la signification d'un namespace-or-type-name.

    • Sinon, en commençant par l’espace de noms dans lequel le namespace-or-type-name se produit, en continuant avec chaque clôture espace de noms (le cas échéant), et se terminant par le namespace global, le suivant les étapes sont évaluées jusqu'à ce qu'une entité soit situé:

    • Si l'espace de noms contient un membre d'espace de noms avec le .__ donné. name, puis le namespace-or-type-name fait référence à ce membre et, selon sur le membre, est classé comme un espace de noms ou un type.

    • Sinon, si l'espace de noms a un .__ correspondant. déclaration d'espace de noms contenant le endroit où le namespace-or-type-name se produit, alors:

    • Si la déclaration d'espace de noms contient un using-alias-directive qui associe le nom donné avec une importée un espace de noms ou un type, puis le namespace-or-type-name fait référence à cela espace de noms ou type.

    • Sinon, si les espaces de noms importés par le fichier using-namespace-directives du La déclaration d'espace de noms contient exactement un type avec le nom donné, puis le namespace-or-type-name fait référence à cela type.
      ...

Cela signifie que lors de la résolution de Foo, sa correspondance avec CompanyName.Foo (premier bit en gras) se produit avant de le faire correspondre à la directive using (deuxième construction en gras).

5
Igor Zevaka

Ce problème est survenu lorsque je faisais référence à une classe dans une bibliothèque de classes distincte, où son type avait le même nom que la racine de l'espace de noms. Initialement, lors de la référence à ce type dans un projet d'application de console séparé, il n'y avait aucun problème, tout était bien compilé. Cependant, la référence d'un projet de service Windows générait le message is a 'namespace' but is used like a 'type'.. Il s'avère que le cadre de la structure cible du projet de service Windows est défini sur "Profil client .NET Framework 4". Changer cela en ".NET Framework 4" a éliminé l'erreur. Espérons que cela aide quelqu'un dans une situation similaire.

1
David Marchelya

Je suis nouveau sur c # et je suis entré en contact avec cette erreur lors de la décompilation d’une application ac #, l’enregistrement en tant que projet, la tentative de recompilation immédiate. .. le problème et la solution sont assez simples: par défaut, lors de l’ajout d’une nouvelle classe, c # utilise le même nom pour un espace de noms que pour la classe dans l’espace de noms !!!!! C'est mauvais parce que sans un identifiant caché indiquant explicitement à quel (espace de noms ou type) vous faites référence, le compilateur ne peut pas faire la différence !!!!! doh! chemin à parcourir c # !!!! ... LA SOLUTION: Au lieu de renommer mille choses et de vérifier toutes les corrections, lancez le projet. Lorsque vous avez la liste des erreurs sous vos yeux, cliquez sur chacune d'elles pour accéder à chaque problème. Une fois sur le "foo" en question, tapez un point (.) Après le mot "foo" tel qu’il affiche: foo. .. cela devrait faire apparaître le menu des classes contenues dans. Dans cette liste, double-cliquez sur "foo" (ou retapez simplement le nom) en remplaçant l'original "foo" par "foo.foo" ... Faites ceci pour chaque erreur et chaque problème résolu !!! Voila !!!! Je l'ai fait à une application entière avec des noms complexes, et cela a très bien fonctionné! Bonne codage! - Tim H.

1
Tim H.

pourquoi tu ne peux pas faire

using CompanyName.Foo; 
... 
public Models.Foo DataContext { get; set; } 
1
alpha

Comme vous avez utilisé la notation par points pour séparer Société et Foo, vous créez implicitement un espace de nom Société, avec un espace de nom Foo imbriqué, et non pas Company.Foo comme vous le croyez. 

C'est pourquoi cela ne fonctionne pas:

namespace Company.Foo
{
}

namespace Company.Foo.Models
{
    public class TestClass {
        public Foo DataContext { get; set; }
    }
}

La chose la plus proche de Foo est l’espace de noms Foo imbriqué dans l’espace de noms Société. Vous pouvez cependant faire ceci:

using Company.Foo;
using Company.Foo.Models;

namespace Company.Foo
{
    class Program {
        public static void Main() {}
    }
}

namespace Company.Foo.Models
{
    public class Foo { }

}

public class DataContextClass
{
    public Foo DataContext { get; set; } /* Foo here is automatically resolved to Company.Foo.Models.Foo */
}

Modifier

Igor a dit la même chose, mais était plus technique. 

0
scottm

Cela se produit également si vous générez des tests unitaires lorsque vous avez un espace de noms et une classe du même nom. Ce que vous ne devriez jamais faire comme l'explique Eric Lippert ici:

http://blogs.msdn.com/b/ericlippert/archive/2010/03/09/do-not-name-a-class-the-same-as-its-namespace-part-one.aspx

0
Jason Axelson