3
votes

Pourquoi ne pouvons-nous pas accéder à la méthode statique via l'objet dans .net

avec le code suivant:

public class test
{
    public static void DoSomething()
    {
        Console.WriteLine("test");
    }
}

public class test2
{
    public test2()
    {
        var a = new test();
        a.DoSomething(); // invalid
        test.DoSomething(); // is valid
    }
}

J'ai besoin d'accéder à la méthode statique via la classe de base, et non via l'instance.

Mais, qu'est-ce qui aurait été l'inconvénient de permettre à l'utilisateur d'y accéder via l'instance? Il me semble que cela aiderait à la lisibilité.

c#

17 commentaires

Ce serait un peu déroutant à mon humble avis, au moins de cette façon, vous savez que c'est statique. Quoi qu'il en soit, le pourquoi, c'est simplement parce que quelqu'un a pris cette décision. Il n'y a pas vraiment d'autre raison.


Non, cela n'aide pas la lisibilité. a.DoSomething (); suggère que vous appelez une méthode d'instance, qui pourrait changer l'état de l'objet ou travailler sur / avec les données de l'objet d'une manière ou d'une autre. Une méthode statique ne fonctionne pas avec / sur l'instance d'objet a , donc purement du point de vue de la lisibilité / maintenabilité du code, ce que vous voulez rend les choses plus sujettes aux erreurs car cela va à l'encontre de l'intuition / des attentes lors de la lecture le code...


"Il me semble que cela aiderait à la lisibilité." Comment cela aiderait-il? Comment feriez-vous la différence entre un appel de membre statique et un appel non statique si cela était autorisé?


Créez une méthode d'extension si vous voulez vraiment faire cela, même si cela échouerait ma révision de code


@HimBromBeere: Je n'ai pas besoin de différencier dans tous les cas; et c'est exactement le point auquel je pense: dans certains cas, savoir que vous appelez explicitement une méthode statique importe, mais dans d'autres cas, cela ne fait aucune différence et je ne comprends pas pourquoi l'utilisation de l'instance n'est pas autorisé puisque vous pouvez également appeler une méthode sur une instance qui ne modifie rien, se comportant comme un statique


Tout ce qui est statique signifie qu'il n'a qu'une seule instance, une fonction est aussi quelque chose en mémoire. Pour cette raison, les instances de "test" ne peuvent pas avoir leur propre fonction "DoSomething ()". Seul "test" lui-même peut avoir la fonction "DoSomething ()", et c'est pourquoi vous l'appelez depuis "test" lui-même. Considérant que chaque instance de "test" est également "un test", on pourrait soutenir que chaque instance de "test" devrait être capable d'appeler la fonction, mais dans un contexte multi-thread, cela pourrait mal tourner par plusieurs instances de "test" essayer d'exécuter la même fonction en même temps.


Eh bien, le compilateur ne sait pas avec certitude si ou sinon votre méthode est non statique alors qu'elle ne change pas l'état des instances. Il faudrait beaucoup de vérifications pour vérifier si votre méthode vraiment ne change pas d’état.


Par exemple, si vous supposez que plusieurs instances de "test" peuvent appeler la fonction statique, dans un environnement multithread, supposez la situation suivante: Instance 1 appelle "DoSomething ()", Instance 2 appelle "DoSomething ()" également. Au milieu de l'écriture de "test" dans DoSomething (), il recommence à être écrit. Le résultat final est "tteesstt" par exemple. Ceci est juste un exemple, mais peut-être que vous comprenez.


Imaginez un nouveau développeur vu tester a = null; a.StaticMethod (); a.InstanceMethod (); Serait-il évident pour eux pourquoi la première ligne de code fonctionne mais pas la seconde? Non, ce ne serait pas - c'est pourquoi ce n'est pas autorisé. Il est vrai que les méthodes d'extension affaiblissent quelque peu cet argument - mais les méthodes d'extension sont moins couramment utilisées que les méthodes normales et n'étaient pas une caractéristique de C # depuis le premier jour comme les méthodes statiques l'étaient.


Rendre quelque chose disponible au niveau de l'instance qui n'a tout simplement pas de sémantique d'instance semble être une bonne idée dans votre monde?


Hrm je pense que cette question devrait être fermée, comme indiqué son pas de réponse dans son format actuel. De plus, je ne sais pas pourquoi tout le monde vote pour tout, peut-être qu'il reste de la pause xmass


Dans le scénario que je regarde, il y a un enregistreur qui contient des données d'instance utilisées par une partie de l'API, mais aussi du code qui ne se soucie pas des données d'instance. L'utiliser en mélangeant les appels d'instance et les appels statiques est déroutant car il se lit comme si nous parlions à deux systèmes différents tandis que la sortie va au même endroit


" savoir que vous appelez explicitement une méthode statique importe, " Donc, vous convenez qu'il est avantageux que le compilateur exige / applique le modèle . , même si dans d'autres situations vous sauriez ce qu'est une méthode statique et ce qui n'est pas une méthode statique, non? " appeler une méthode sur une instance qui ne modifie rien, se comportant comme un statique " Ce n'est pas une raison ou un exemple généralement significatif. (1/2)


Je pense que vous avez en fait un problème de séparation des préoccupations (juste une supposition)


par exemple var L = new Logger (); ... L.Log (this stuff); Logger.Logx (autre chose) dans le code n'est pas aussi lisible que d'accéder à tout via L


(2/2) Une méthode d'instance est supposée être associée (travailler sur) l'instance sur laquelle elle est appelée. C'est pourquoi les méthodes d'instance (IM) sont des méthodes d'instance pour commencer. Si vous écrivez une méthode d'instance qui ne fonctionne pas sur l'instance sur laquelle elle est appelée, transformez-la en méthode statique. Si vous avez un tel IM parce qu'il est stipulé par un contrat (interface, classe de base abstraite), alors un tel IM est censé fonctionner sur l'instance sur laquelle il est appelé, et ce serait simplement dû aux circonstances spécifiques de la classe dérivée si un tel IM ne devait pas avoir besoin de travailler avec l'objet sur lequel il est appelé.


(De plus, pour ajouter à mon (2/2) commentaire, les classes implémentent parfois des méthodes vides remplaçables pour garder cette classe instanciable tout en donnant aux classes dérivantes des points bien définis pour étendre le comportement. Encore une fois, cela ne fonctionne pas. signifie vraiment que de telles méthodes ne sont pas censées fonctionner sur l'objet. Les méthodes remplaçant ces méthodes vides remplaçables sont censées fonctionner sur l'instance d'objet sur laquelle elles sont appelées)


6 Réponses :


7
votes

Vous ne pouvez pas appeler une méthode statique à partir d'une instance de classe, car tous les champs et méthodes statiques sont associés au type plutôt qu'à une instance dudit type.

Pour une compréhension approfondie des classes statiques, je vous suggère de lire this .


3 commentaires

J'ajouterais également qu'il s'agit d'un détail d'implémentation dans la spécification du langage C #. D'autres langages comme Python permettent d'accéder aux membres statiques à partir d'une instance.


C'est vrai. Je n'ajouterais qu'un lien vers la documentation officielle de Microsoft: static-classes-and-static-class-members


Je suggère d'ajouter le lien suivant: static (C # Reference )



0
votes

Vous pouvez également créer la méthode statique comme méthode d'extension sur la classe de base ou la classe enfant. Ensuite, vous pouvez l'appeler directement à partir de l'instance d'objet lorsque vous avez tenté.


0 commentaires

0
votes

Utiliser instance.DoSomething (); indiquerait que vous appelez une méthode de l'instance (ce qui, bien sûr, ne serait pas vrai car il s'agit d'un membre de classe statique, non lié à l'instance elle-même) . Pour cette raison, cela ne ferait probablement que semer la confusion.

En utilisant MyClass.DoSomething (); on comprend facilement qu'il s'agit en fait d'un membre de la classe (et non d'une instance) que vous appelez. Ce sera peut-être plus clair si vous suivez les conventions de dénomination standard (nom de classe avec une majuscule en tête).

Pour une meilleure compréhension des membres statiques, consultez le Microsoft docs .


0 commentaires

0
votes

Comme pour chaque question sur une décision linguistique, vous devez toujours tenir compte de l'utilisation et du préjudice potentiel causé par votre demande. Bien que cela puisse augmenter votre lisibilité (personnelle) dans un cas très spécifique, cela ajoute beaucoup de confusion aux lecteurs de votre code qui n'ont pas votre code source. De plus, cela supposerait qu'un compilateur soit capable de déterminer si ou non un membre fait réellement quelque chose sur l'instance ou non. Ainsi, le compilateur aurait une logique beaucoup plus compliquée afin de réaliser quelque chose que vous pouvez facilement vous indiquer par le mot-clé static .

En fait, une méthode instance fait quelque chose avec une instance , elle ne modifie pas nécessairement son état, elle peut aussi simplement utiliser cet état et traiter une opération. Rendre quelque chose disponible à ce niveau d'instance qui n'a pas de sémantique d'instance semble tout à fait contre-intuitif et brise le principe du moindre étonnement - du moins pour moi. Si un membre est appelé sur une instance, il est supposé faire quelque chose avec cette instance. Si c'est le cas ou si ce n'est pas le cas, c'est un détail d'implémentation pour lequel un client ne devrait pas se soucier du tout.


1 commentaires

Je pense que c'est la bonne réponse: dans le cas pratique dont je parle, cela rend la syntaxe beaucoup moins lisible, mais en général, il est probable que la séparation ait un sens.



-1
votes

Je pense que c'est la ligne clé de la documentation:

Une seule copie d'un membre statique existe, quel que soit le nombre des instances de la classe sont créées.


0 commentaires

1
votes

Je suppose que ce que vous demandez est

Lors de l'appel d'une méthode statique, pourquoi nous devons spécifier la classe qui définit la méthode et lors de l'appel d'une méthode d'instance, pourquoi nous devons spécifiez une instance qui fait référence à l'objet de cette classe.

Pour répondre à cela, nous devons comprendre comment CLR gère les choses en arrière-plan. Essayons de comprendre ce qui se passe lorsqu'une nouvelle instance est créée:

Lorsque nous " nouveau " une instance de classe, le CLR crée un objet dans le tas géré , cet objet sur le tas (entre autres) contient également les octets nécessaires pour contenir tous les champs de données d'instance définis par cette classe ainsi que tous les champs d'instance définis par n'importe quelle classe de base (par exemple la classe Object ). Cela signifie que les champs d'instance sont liés à cette instance de la classe que nous venons de créer en newing dans notre code.

Désormais, lors de l'appel d'une méthode statique, le compilateur JIT localise l'objet de classe qui correspond au type qui définit la méthode statique. Notez qu'il n'utilise pas l'instance (objet) ici. Ensuite, le compilateur JIT localise l’entrée dans la table des méthodes de l’objet de classe qui fait référence à la méthode appelée, JIT la méthode (si elle est appelée pour la première fois) et appelle le code JITted. Notez la différence dans la façon dont CLR effectue la découverte d'une instance et des méthodes statiques.


3 commentaires

La question est de savoir pourquoi nous ne pouvons pas accéder aux méthodes statiques à partir d'un objet; La conclusion de la discussion semble être que la façon dont il est maintenant a du sens dans la plupart des cas, et je comprends pourquoi. Mon point est que dans certains cas, cela rend le code qui l'utilise moins lisible car quelqu'un qui utilise une API peut ne pas vraiment se soucier de ce qui est statique ou non, mais cela ne semble vrai que dans certains cas spécifiques.


@Thomas - Je ne pense pas avoir bien compris votre commentaire. Votre question suggère que la réponse se trouve sur la façon dont le CLR gère l'instance et les méthodes statiques au moment de l'exécution, cela n'a rien à voir avec la lisibilité du code.


Le point principal se trouve au bas de ma question: "Mais, quel aurait été l'inconvénient de laisser l'utilisateur y accéder via l'instance?" Il s'agit d'une décision de conception, le CLR a été mis en œuvre en conséquence, suite à ce choix de conception.