46 votes

L'"héritage" d'un membre statique en C# - pourquoi cela existe-t-il ?

En C#, les membres statiques d'une superclasse sont "hérités" dans la portée des sous-classes. Par exemple, les membres statiques d'une superclasse sont "hérités" dans la portée des sous-classes :

class A { public static int M() { return 1; } }
class B : A {}
class C : A { public new static int M() { return 2; } }
[...]
A.M(); //returns 1
B.M(); //returns 1 - this is equivalent to A.M()
C.M(); //returns 2 - this is not equivalent to A.M()

Vous ne pouvez pas hériter de classes statiques, et le seul endroit où je peux imaginer que l'héritage statique pourrait avoir de l'importance l'ignore complètement : bien que vous puissiez créer une contrainte générique qui exige un paramètre de type T pour être une sous-classe de A vous ne pouvez toujours pas appeler T.M() (ce qui simplifie probablement les choses pour la VM), sans parler de l'écriture d'un M dans une sous-classe et l'utiliser.

Ainsi, l'"héritage" des membres statiques ressemble simplement à une pollution de l'espace de noms ; même si vous qualifiez explicitement le nom (c.-à-d. B.M ) A est toujours résolue.

Editer comparer avec les espaces de noms :

namespace N1{  class X();   }
namespace N1.N2 {  class X();   }
namespace N1.N2.N3 { [...] }

A l'intérieur N1.N2.N3 Il est logique que si j'utilise X sans qualification, il s'agit de N1.N2.X . Mais si je me réfère explicitement à N1.N2.N3.X - et qu'une telle classe n'existe pas - je ne m'attends pas à ce qu'il trouve N2 et le compilateur signale d'ailleurs une erreur si vous essayez de le faire. En revanche, si je fais explicitement référence à B.M() Pourquoi le compilateur ne signale-t-il pas d'erreur ? Après tout, il n'y a pas de méthode "M" dans "B"...

Quel est l'objectif de cet héritage ? Cette caractéristique peut-elle être utilisée de manière constructive d'une manière ou d'une autre ?

27voto

Daniel Earwicker Points 63298

Ainsi, l'"héritage" des membres statiques ressemble simplement à un espace de noms pollution

C'est vrai, sauf que la pollution des uns est l'arôme épicé des autres.

Je pense que Martin Fowler, dans son travail sur les DSL, a suggéré d'utiliser l'héritage de cette manière pour permettre un accès pratique aux méthodes statiques, permettant à ces méthodes d'être utilisées sans qualification du nom de la classe. Le code d'appel doit donc se trouver dans une classe qui hérite de la classe dans laquelle les méthodes sont définies. (Je pense que c'est une idée pourrie).

À mon avis, les membres statiques ne devraient pas être mélangés à une classe dont l'objectif n'est pas statique, et le problème que vous soulevez ici est l'une des raisons pour lesquelles il est important de ne pas les mélanger.

Masquage des données statiques privées mutable à l'intérieur de l'implémentation d'une classe par ailleurs "instancey" est particulièrement horrible. Mais il y a aussi les méthodes statiques, qui sont des mélangeurs encore pires. Voici un exemple typique d'utilisation de méthodes statiques dans une classe :

public class Thing
{
    // typical per-instance stuff
    int _member1;
    protected virtual void Foo() { ... }
    public void Bar() { ... }

    // factory method
    public static Thing Make()
    {
        return new Thing();
    }
}

Il s'agit du modèle de la méthode d'usine statique. C'est inutile la plupart du temps, mais ce qui est encore pire, c'est que maintenant nous avons ceci :

public class AnotherThing : Thing { }

Il dispose désormais d'une fonction statique Make qui renvoie un Thing et non un AnotherThing .

Ce type de décalage implique fortement que tout ce qui comporte des méthodes statiques doit être scellé. Les membres statiques ne s'intègrent pas bien à l'héritage. Cela n'a aucun sens de les rendre héritables. Je garde donc les éléments statiques dans des classes statiques distinctes et je me plains de devoir déclarer chaque membre statique alors que j'ai déjà dit que la classe était statique.

Mais ce n'est qu'une de ces choses trop tardives. Tous les langages (et bibliothèques, et produits) réels et fonctionnels en ont quelques-uns. C# en a remarquablement peu.

10voto

Luis Filipe Points 3302

Je préfère avoir accès à tous mes membres statiques dans les classes dérivées. Sinon, je devrais savoir exactement où le membre statique a été défini et l'appeler explicitement.

L'utilisation d'Intellisense permet de connaître automatiquement tous les membres statiques disponibles pour ce type de classe.

Bien entendu, ils ne sont pas hérités, il s'agit simplement d'un raccourci.

8voto

Filip Ekberg Points 22189

C'est ainsi que cela fonctionne Dans la plupart des cas, il s'agirait d'une réponse stupide. Mais dans ce cas, c'est ainsi que cela fonctionne ; puisque vous dérivez de A, vous dites que vous êtes A + les caractéristiques supplémentaires que vous ajoutez.

Par conséquent, vous devez être en mesure d'accéder aux mêmes variables que vous le feriez par le biais d'une instance de A.

Cependant, hériter d'une classe statique n'a pas de sens alors que l'accès aux membres, champs et méthodes statiques en a un.

En voici un exemple :

internal class BaseUser
{
    public static string DefaultUserPool { get; set; }
}
internal class User : BaseUser
{
    public int Id { get; set; }
    public string Name { get; set; }
    public User Parent { get; set; }
}

Le test se présente comme suit :

User.DefaultUserPool = "Test";
BaseUser.DefaultUserPool = "Second Test";

Console.WriteLine(User.DefaultUserPool);
Console.WriteLine(BaseUser.DefaultUserPool);

Les deux lignes d'écriture affichent "Second Test", car BaseUser et User doivent utiliser DefaultUserPool, par conception . Et surcharger les méthodes statiques implémentées n'aurait pas beaucoup de sens puisque c'est juste un accesseur dans la classe enfant.

Il ne peut y en avoir qu'un seul. La remplacer signifierait qu'il existe une nouvelle implémentation pour cette sous-classe, ce qui tuerait le terme "statique".

5voto

Vilx- Points 37939

En fait, si j'ai bien compris, il s'agit d'un raccourci fourni par le compilateur. Sucre de syntaxe. B.M() se compilera simplement en A.M() puisque B n'a pas de static M() et A le fait. C'est pour faciliter l'écriture, rien d'autre. Il n'y a pas d'"héritage statique".

Ajouté : Et l'exigence de new quand la "redéfinition" est juste pour ne pas se tirer accidentellement une balle dans le pied.

0voto

ChrisBD Points 5795

J'y vois toujours un moyen d'empêcher toute forme de polymorphisme de la part de la classe héritante sur les éléments dont vous souhaitez conserver la même fonction pour toutes les classes enfants.

ignorer ce qui précède pour une raison quelconque, j'ai pensé à sealed au lieu de static

Je suppose que vous utiliseriez des variables membres et des fonctions statiques afin de garantir que les données ou les fonctions ne dépendent pas d'une instance de la classe puisqu'elles ne seraient instanciées qu'une seule fois.

Un exemple d'utilisation serait une valeur de compteur qui tiendrait un compte en temps réel de toutes les instances des sous-classes d'une superclasse (chaque sous-classe incrémente la valeur statique du compteur lors de sa construction). Cette valeur de comptage serait disponible et égale pour toutes les instances de la sous-classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X