web-dev-qa-db-fra.com

Interface interne C # avec implémentation interne

J'ai frappé quelque chose que je ne comprends pas vraiment.

J'ai un projet, où j'ai une interface interne. La classe qui implémente cette interface est également interne. Dans l'implémentation de l'interface, je rend tous les membres que j'implémente, internes. Je n'ai pas fait d'implémentation explicite.

J'ai deux interfaces et deux classes qui implémentent ces interfaces où cela fonctionne bien.

Cela ressemblerait à quelque chose comme ceci:

internal interface IA
{
    void X();
}

puis

internal class CA : IA
{
    internal void X()
    {
        ...
    }
}

Cela fonctionne bien pour les deux classes susmentionnées. Mais quand j'essaye de le faire avec une autre interface et classe, cela ne fonctionne pas. En fait, pour l'exemple ci-dessus, j'obtiens l'erreur:

'WindowsFormsApplication1.CA' n'implémente pas le membre d'interface 'WindowsFormsApplication1.IA.X ()'. 'WindowsFormsApplication1.CA.X ()' ne peut pas implémenter un membre d'interface car il n'est pas public.

Je me rends compte que je peux rendre les méthodes publiques ou faire une implémentation explicite (et omettre les modificateurs internes et publics), mais je suis simplement confus quant à la raison pour laquelle cela fonctionne avec les deux classes avec lesquelles il fonctionne et pourtant je semble incapable de répliquer ailleurs.

Boucher un peu le code (car il est confidentiel), c'est l'un de ceux qui fonctionnent réellement dans mon projet.

internal interface IScanner
{
    void SetHardware(Hardware hardware);
    void Start();
    void PauseScan();
    void ResumeScan();
    void Stop();
    bool InScan { get; }
    event ScanCompleteHandler ScanComplete;
}

Ensuite, j'ai la classe:

internal class MyScanner : IScanner
{
    internal void SetHardware(Hardware hardware)
    {
       ...
    }

    internal void Start()
    {
        ...
    }

    internal void Stop()
    {
        ...
    }

    internal void PauseScan()
    {
        ...
    }

    internal void ResumeScan()
    {
        ...
    }

    internal bool InScan
    {
        get
        {
            ...
        }
    }

    internal event ScanCompleteHandler ScanComplete;
}

Pour rendre les choses encore plus étranges, j'ai créé une autre classe interne appelée Temp. Je l'ai ensuite fait implémenter l'interface IScanner et j'ai copié et collé l'implémentation de MyScanner dessus et il ne se compilera pas, me donnant l'erreur que: "ne peut pas implémenter un membre d'interface car il n'est pas public."

Quelqu'un peut-il expliquer cette incohérence?

Merci

(Mis à jour pour corriger une faute de frappe et clarifier du texte)

MODIFIER: Informations supplémentaires

J'ai exécuté le code via le réflecteur et mes implémentations ont été compilées en tant qu'implémentations explicites, même si elles ne sont pas explicites. Le réflecteur ne montre aucun signe des mots clés internes. Tout ce que je peux deviner, c'est que c'est une sorte de problème dans le compilateur qui, pour une raison quelconque, m'a permis de les rendre internes et implicites et qu'il a en quelque sorte résolu cela comme étant une implémentation explicite.

J'ai parcouru le code plusieurs fois. Je ne trouve aucune autre explication à cela.

42
Pete

Si vous implémentez implicitement une interface, je pense que le membre doit être déclaré public. Dans votre exemple, CA tente d'implémenter implicitement la méthode X() mais n'est pas déclaré public. Si vous souhaitez conserver X() comme interne, vous devez utiliser une implémentation d'interface explicite.

void IA.X() { /* stuff */ }

Cependant, j'ajouterai également que rendre la méthode X() publique ne ferait pas de mal de toute façon car la classe est interne de sorte que le membre est déjà restreint par ce modificateur d'accès ... Autrement dit, c'est déjà effectivement interne ... Donc, vous pourriez aussi bien le rendre public!

20
Reddog

Je sais que cela fait un certain temps que cette question n'a pas été posée, mais je peux peut-être éclairer la question. Selon la spécification du langage C # trouvée ici le comportement que vous avez décrit ne devrait pas être possible. Parce que sous 20.4.2 Mappage d'interface, il est dit que l'implémentation est explicite ou mappée à un membre public non statique. Donc, soit vous avez un autre scénario que celui que vous décrivez ici, soit vous avez trouvé un bogue dans votre compilateur :).

3
S. Larws

Il est OK d'avoir un modificateur interne dans une déclaration d'interface, mais vous ne pouvez pas avoir de modificateurs à l'intérieur de l'interface, en d'autres termes, vous ne pouvez pas avoir de modificateur pour les membres de l'interface. C'est aussi simple que ça!

Exemple:

internal interface IA
{
    void X(); //OK. It will work
}


internal class CA : IA
{
    **internal** void X() // internal modifier is NOT allowed on any Interface members. It doesn't compile. If it works in your project it's because either you DON'T have the void X() method in the Interface or your are inheriting from a wrong interface maybe accidentally 
    {
        ...
    }
}

Une déclaration d'interface peut déclarer zéro ou plusieurs membres. Les membres d'une interface doivent être des méthodes, des propriétés, des événements ou des indexeurs. Une interface ne peut pas contenir de constantes, de champs, d'opérateurs, de constructeurs d'instance, de destructeurs ou de types, pas plus qu'une interface ne peut contenir de membres statiques d'aucune sorte. Tous les membres de l'interface ont implicitement un accès public. C'est une erreur au moment de la compilation que les déclarations des membres de l'interface incluent tous les modificateurs. En particulier, les membres des interfaces ne peuvent pas être déclarés avec les modificateurs abstract, public, protected, internal, private, virtual, override ou static.

Référence: https://docs.Microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/interfaces

2
Rick

Probablement que votre classe "Temp" est publique et IScanner est interne. C'est la raison pour laquelle vous obtenez cette erreur. Je considère cela très ennuyeux car vous êtes obligé de l'implémenter explicitement, vous ne pouvez pas les spécifier comme abstraits ou virtuels. Pour le truc virtuel, j'ai été forcé de faire une implémentation virtuelle interne implicite de la même API, puis d'appeler la version implicite à partir de la version explicite. Laid.

2
NoNameStackExchange

À ma connaissance, vous ne pouvez pas implémenter les méthodes d'interface internal. Comme vous l'avez dit, vous pouvez les implémenter explicitement, mais quelqu'un peut toujours faire ((IScanner)myScanner).SetHardware(hw)

Êtes-vous sûr à 100% que votre implémentation MyScanner ne fait pas quelque chose comme ceci:

internal class MyScanner : IScanner
{
    void IScanner.SetHardware(Hardware hardware) { this.SetHardware(hardware); }
    internal void SetHardware(Hardware hardware)
    {
      ...
    }
    ....
}

ou ca:

internal partial class MyScanner : IScanner
{
    internal void SetHardware(Hardware hardware)
    {
        ...
    }
}

internal partial class MyScanner
{
    void IScanner.SetHardware(Hardware hardware)
    {
        this.SetHardware(hardware);
    }
}
0
ChrisWue