Pourquoi C # a-t-il été conçu de cette façon?
Si je comprends bien, une interface ne décrit que le comportement, et sert à décrire une obligation contractuelle pour les classes implémentant l'interface que certains comportements sont mis en œuvre.
Si les classes souhaitent implémenter ce comportement dans une méthode partagée, pourquoi pas?
Voici un exemple de ce que j'ai en tête:
// These items will be displayed in a list on the screen.
public interface IListItem {
string ScreenName();
...
}
public class Animal: IListItem {
// All animals will be called "Animal".
public static string ScreenName() {
return "Animal";
}
....
}
public class Person: IListItem {
private string name;
// All persons will be called by their individual names.
public string ScreenName() {
return name;
}
....
}
c#
oop
language-features
Kramii
la source
la source
IListItem.ScreenName() => ScreenName()
(en utilisant la syntaxe C # 7) implémentera explicitement la méthode d'interface en appelant la méthode statique. Les choses tournent mal quand vous ajoutez l'héritage à cela, cependant (vous devez réimplémenter l'interface)Réponses:
En supposant que vous demandez pourquoi vous ne pouvez pas faire cela:
Cela n'a pas de sens pour moi, sémantiquement. Les méthodes spécifiées sur une interface doivent être là pour spécifier le contrat d'interaction avec un objet. Les méthodes statiques ne vous permettent pas d'interagir avec un objet - si vous vous trouvez dans la position où votre implémentation pourrait être rendue statique, vous devrez peut-être vous demander si cette méthode appartient vraiment à l'interface.
Pour implémenter votre exemple, je donnerais à Animal une propriété const, qui lui permettrait toujours d'être accessible à partir d'un contexte statique, et retournerait cette valeur dans l'implémentation.
Pour une situation plus compliquée, vous pouvez toujours déclarer une autre méthode statique et y déléguer. En essayant de trouver un exemple, je ne pouvais penser à aucune raison pour laquelle vous feriez quelque chose de non trivial à la fois dans un contexte statique et d'instance, donc je vous épargnerai un blob FooBar, et le considérerai comme une indication qu'il pourrait pas une bonne idée.
la source
public static object MethodName(this IBaseClass base)
au sein d'une classe statique. L'inconvénient, cependant, est que contrairement à un héritage d'interface - cela ne force pas / ne permet pas aux héritiers individuels de bien remplacer la méthodologie.Ma raison technique (simplifiée) est que les méthodes statiques ne sont pas dans le vtable , et le site d'appel est choisi au moment de la compilation. C'est la même raison pour laquelle vous ne pouvez pas avoir de remplacement ou de membres statiques virtuels. Pour plus de détails, vous auriez besoin d'un won CS grad ou compilateur - dont je ne suis pas un.
Pour des raisons politiques, je citerai Eric Lippert (qui est un gagnant de compilateur et titulaire d'un baccalauréat en mathématiques, informatique et mathématiques appliquées de l'Université de Waterloo (source: LinkedIn ):
Notez que Lippert laisse de la place à une méthode dite de type:
mais doit encore être convaincu de son utilité.
la source
object
s et comment ils sont autorisés à implémenter des interfaces.La plupart des réponses semblent manquer ici. Le polymorphisme peut être utilisé non seulement entre les instances, mais également entre les types. Cela est souvent nécessaire lorsque nous utilisons des génériques.
Supposons que nous ayons un paramètre de type dans la méthode générique et que nous ayons besoin de faire une opération avec. Nous ne voulons pas instancier, car nous ignorons les constructeurs.
Par exemple:
Malheureusement, je ne peux proposer que des alternatives "laides":
Utilisez la réflexion Ugly et bat l'idée des interfaces et du polymorphisme.
Créer une classe d'usine complètement séparée
Cela pourrait augmenter considérablement la complexité du code. Par exemple, si nous essayons de modéliser des objets de domaine, chaque objet aurait besoin d'une autre classe de référentiel.
Instancier puis appeler la méthode d'interface souhaitée
Cela peut être difficile à implémenter même si nous contrôlons la source des classes, utilisées comme paramètres génériques. La raison en est que, par exemple, nous pourrions avoir besoin que les instances soient uniquement dans un état "connecté à la base de données" bien connu.
Exemple:
afin d'utiliser l'instanciation pour résoudre le problème d'interface statique, nous devons faire la chose suivante:
C'est évidemment laid et complique également le code pour toutes les autres méthodes. Évidemment, ce n'est pas non plus une solution élégante!
la source
public abstract class DBObject<T> where T : DBObject<T>, new()
puis de faire hériter toutes les classes DBDBObject<T>
. Ensuite, vous pouvez faire de la récupération par clé une fonction statique avec le type de retour T dans la superclasse abstraite, faire en sorte que cette fonction crée un nouvel objet de T, puis appeler un objet protégéString GetRetrieveByKeyQuery()
(défini comme abstrait sur la superclasse) sur cet objet pour obtenir la requête réelle à exécuter. Bien que cela puisse être un peu hors sujetJe sais que c'est une vieille question, mais c'est intéressant. L'exemple n'est pas le meilleur. Je pense que ce serait beaucoup plus clair si vous montriez un cas d'utilisation:
Le simple fait d'avoir des méthodes statiques implémentant une interface ne permettrait pas d'atteindre ce que vous voulez; ce qui serait nécessaire serait d'avoir des membres statiques dans le cadre d'une interface. Je peux certainement imaginer de nombreux cas d'utilisation pour cela, surtout quand il s'agit de pouvoir créer des choses. Je pourrais proposer deux approches qui pourraient être utiles:
Aucune de ces approches n'est vraiment attrayante. D'un autre côté, je m'attendrais à ce que si les mécanismes existaient dans CLR pour fournir ce type de fonctionnalité proprement, .net permettrait de spécifier des "nouvelles" contraintes paramétrées (car savoir si une classe a un constructeur avec une signature particulière semblerait être comparable en difficulté à savoir si elle a une méthode statique avec une signature particulière).
la source
Myopie, je suppose.
Lors de leur conception initiale, les interfaces étaient uniquement destinées à être utilisées avec des instances de classe
Ce n'est qu'avec l'introduction des interfaces que les contraintes pour les génériques ont fait que l'ajout d'une méthode statique à une interface avait une utilité pratique.
(répondant au commentaire :) Je crois que le changer maintenant nécessiterait une modification du CLR, ce qui entraînerait des incompatibilités avec les assemblages existants.
la source
Les interfaces spécifient le comportement d'un objet.
Les méthodes statiques ne spécifient pas le comportement d'un objet, mais un comportement qui affecte un objet d'une manière ou d'une autre.
la source
Dans la mesure où les interfaces représentent des "contrats", il semble raisonnable pour les classes statiques d'implémenter des interfaces.
Les arguments ci-dessus semblent tous manquer ce point sur les contrats.
la source
Parce que le but d'une interface est de permettre le polymorphisme, de pouvoir passer une instance de n'importe quel nombre de classes définies qui ont toutes été définies pour implémenter l'interface définie ... garantissant qu'au sein de votre appel polymorphe, le code pourra trouver la méthode que vous appelez. cela n'a aucun sens de permettre à une méthode statique de mettre en œuvre l'interface,
Comment appelleriez-vous ça ??
la source
Whatever<T>() where T:IMyStaticInterface
je pourrais appelerWhatever<MyClass>()
et avoirT.MyStaticMethod()
à l'intérieur de l'Whatever<T>()
implémentation sans avoir besoin d'une instance. La méthode à appeler serait déterminée lors de l'exécution. Vous pouvez le faire via la réflexion, mais il n'y a pas de "contrat" à forcer.En ce qui concerne les méthodes statiques utilisées dans des contextes non génériques, je suis d'accord que cela n'a pas beaucoup de sens de les autoriser dans les interfaces, puisque vous ne seriez pas en mesure de les appeler si vous aviez une référence à l'interface de toute façon. Cependant, il y a un trou fondamental dans la conception du langage créé en utilisant des interfaces NON dans un contexte polymorphe, mais dans un contexte générique. Dans ce cas, l'interface n'est pas du tout une interface mais plutôt une contrainte. Parce que C # n'a pas de concept de contrainte en dehors d'une interface, il lui manque des fonctionnalités substantielles. Exemple concret:
Ici, il n'y a pas de polymorphisme, le générique utilise le type réel de l'objet et appelle l'opérateur + =, mais cela échoue car il ne peut pas dire avec certitude que cet opérateur existe. La solution simple est de le spécifier dans la contrainte; la solution simple est impossible car les opérateurs sont statiques et les méthodes statiques ne peuvent pas être dans une interface et (voici le problème) les contraintes sont représentées comme des interfaces.
Ce dont C # a besoin est un véritable type de contrainte, toutes les interfaces seraient également des contraintes, mais toutes les contraintes ne seraient pas des interfaces, alors vous pourriez faire ceci:
Il a déjà été beaucoup question de créer une IArithmétique pour tous les types numériques à implémenter, mais il y a des inquiétudes quant à l'efficacité, car une contrainte n'est pas une construction polymorphe, la création d'une contrainte CArithmétique résoudrait ce problème.
la source
T
devrait avoir un statique membre (par exemple, une usine qui produit desT
instances). Même sans changements d'exécution, je pense qu'il serait possible de définir des conventions et des méthodes d'assistance qui permettraient aux langages d'implémenter une chose telle que le sucre syntaxique de manière efficace et interopérable. Si pour chaque interface avec des méthodes statiques virtuelles, il y avait une classe d'assistance ...Parce que les interfaces sont dans une structure d'héritage et que les méthodes statiques n'héritent pas bien.
la source
Ce que vous semblez vouloir permettre à une méthode statique d'être appelée via le Type ou n'importe quelle instance de ce type. Cela entraînerait au moins une ambiguïté qui n'est pas un trait souhaitable.
Il y aurait des débats interminables pour savoir si cela importait, ce qui est la meilleure pratique et s'il y a des problèmes de performance dans un sens ou dans un autre. En ne le supportant simplement pas, C # nous évite de nous en préoccuper.
Il est également probable qu'un compilateur conforme à ce désir perdrait certaines optimisations qui pourraient s'accompagner d'une séparation plus stricte entre les méthodes d'instance et les méthodes statiques.
la source
Vous pouvez considérer les méthodes statiques et les méthodes non statiques d'une classe comme étant des interfaces différentes. Lorsqu'elles sont appelées, les méthodes statiques se résolvent en l'objet de classe statique singleton et les méthodes non statiques se résolvent en l'instance de la classe avec laquelle vous traitez. Donc, si vous utilisez des méthodes statiques et non statiques dans une interface, vous déclareriez effectivement deux interfaces alors que nous voulons vraiment que les interfaces soient utilisées pour accéder à une chose cohérente.
la source
Pour donner un exemple où il me manque soit l'implémentation statique de méthodes d'interface ou ce que Mark Brackett a présenté comme la "méthode dite de type":
Lors de la lecture à partir d'un stockage de base de données, nous avons une classe DataTable générique qui gère la lecture à partir d'une table de n'importe quelle structure. Toutes les informations spécifiques à une table sont placées dans une classe par table qui contient également des données pour une ligne de la base de données et qui doit implémenter une interface IDataRow. Inclus dans IDataRow est une description de la structure de la table à lire dans la base de données. Le DataTable doit demander la structure de données à l'IDataRow avant de lire à partir de la base de données. Actuellement, cela ressemble à ceci:
GetDataStructure n'est requis qu'une seule fois pour chaque table à lire, la surcharge pour l'instanciation d'une autre instance est minime. Cependant, ce serait bien dans ce cas ici.
la source
FYI: Vous pouvez obtenir un comportement similaire à ce que vous voulez en créant des méthodes d'extension pour l'interface. La méthode d'extension serait un comportement statique partagé et non remplaçable. Cependant, malheureusement, cette méthode statique ne ferait pas partie du contrat.
la source
Les interfaces sont des ensembles abstraits de fonctionnalités disponibles définies.
Qu'une méthode dans cette interface se comporte ou non comme statique est un détail d'implémentation qui doit être caché derrière l'interface . Il serait faux de définir une méthode d'interface comme statique, car vous forceriez inutilement la méthode à être implémentée d'une certaine manière.
Si les méthodes étaient définies comme statiques, la classe implémentant l'interface ne serait pas aussi encapsulée qu'elle pourrait l'être. L'encapsulation est une bonne chose à rechercher dans la conception orientée objet (je n'entrerai pas dans le pourquoi, vous pouvez le lire ici: http://en.wikipedia.org/wiki/Object-oriented ). Pour cette raison, les méthodes statiques ne sont pas autorisées dans les interfaces.
la source
Les classes statiques devraient pouvoir le faire pour pouvoir être utilisées de manière générique. J'ai dû à la place implémenter un Singleton pour obtenir les résultats souhaités.
J'ai eu un tas de classes Static Business Layer qui ont implémenté des méthodes CRUD comme "Créer", "Lire", "Mettre à jour", "Supprimer" pour chaque type d'entité comme "Utilisateur", "Équipe", ect .. Ensuite, j'ai créé une base contrôle qui avait une propriété abstraite pour la classe Business Layer qui implémentait les méthodes CRUD. Cela m'a permis d'automatiser les opérations "Créer", "Lire", "Mettre à jour", "Supprimer" de la classe de base. J'ai dû utiliser un Singleton à cause de la limitation statique.
la source
La plupart des gens semblent oublier que dans les classes OOP, il y a aussi des objets, et donc ils ont des messages, qui pour une raison quelconque c # appelle "méthode statique". Le fait qu'il existe des différences entre les objets d'instance et les objets de classe ne montre que des failles ou des lacunes dans le langage. Optimiste sur c # si ...
la source
OK, voici un exemple de besoin d'une «méthode de type». Je crée l'un d'un ensemble de classes basé sur du XML source. J'ai donc un
fonction qui est appelée à son tour sur chaque classe.
La fonction doit être statique car sinon nous perdons du temps à créer des objets inappropriés. Comme le souligne @Ian Boyde, cela pourrait être fait dans une classe d'usine, mais cela ajoute simplement de la complexité.
Ce serait bien de l'ajouter à l'interface pour forcer les implémenteurs de classe à l'implémenter. Cela n'entraînerait pas de surcharge importante - ce n'est qu'une vérification de l'heure de compilation / liaison et n'affecte pas la table virtuelle.
Cependant, ce serait également une amélioration assez mineure. Comme la méthode est statique, moi en tant qu'appelant, je dois l'appeler explicitement et donc obtenir une erreur de compilation immédiate si elle n'est pas implémentée. Le permettre d'être spécifié sur l'interface signifierait que cette erreur survient légèrement plus tôt dans le cycle de développement, mais cela est trivial par rapport à d'autres problèmes d'interface brisée.
Il s'agit donc d'une caractéristique potentielle mineure qui, dans l'ensemble, est probablement préférable de la laisser de côté.
la source
Le fait qu'une classe statique soit implémentée en C # par Microsoft en créant une instance spéciale d'une classe avec les éléments statiques n'est qu'une bizarrerie sur la façon dont la fonctionnalité statique est obtenue. Ce n'est pas un point théorique.
Une interface DEVRAIT être un descripteur de l'interface de classe - ou comment elle est interagie avec, et qui devrait inclure des interactions qui sont statiques. La définition générale de l'interface (de Meriam-Webster): l'endroit ou l'espace où différentes choses se rencontrent et communiquent ou s'influencent. Lorsque vous omettez complètement les composants statiques d'une classe ou les classes statiques, nous ignorons de grandes sections de la façon dont ces mauvais garçons interagissent.
Voici un exemple très clair où pouvoir utiliser des interfaces avec des classes statiques serait très utile:
Actuellement, j'écris les classes statiques qui contiennent ces méthodes sans aucune vérification pour m'assurer que je n'ai rien oublié. C'est comme le mauvais vieux temps de programmation avant OOP.
la source
C # et le CLR doivent prendre en charge les méthodes statiques dans les interfaces comme Java le fait. Le modificateur statique fait partie d'une définition de contrat et a un sens, en particulier le fait que le comportement et la valeur de retour ne varient pas en fonction de l'instance bien qu'il puisse toujours varier d'un appel à l'autre.
Cela dit, je recommande que lorsque vous souhaitez utiliser une méthode statique dans une interface et que vous ne le pouvez pas, utilisez plutôt une annotation. Vous obtiendrez la fonctionnalité que vous recherchez.
la source
Je pense que la réponse courte est "parce qu'elle n'a aucune utilité". Pour appeler une méthode d'interface, vous avez besoin d'une instance du type. À partir des méthodes d'instance, vous pouvez appeler toutes les méthodes statiques de votre choix.
la source
Je pense que la question est de savoir que C # a besoin d'un autre mot-clé, précisément pour ce genre de situation. Vous voulez une méthode dont la valeur de retour dépend uniquement du type sur lequel elle est appelée. Vous ne pouvez pas l'appeler "statique" si ce type est inconnu. Mais une fois que le type sera connu, il deviendra statique. "Statique non résolu" est l'idée - ce n'est pas encore statique, mais une fois que nous connaîtrons le type de réception, il le sera. C'est un très bon concept, c'est pourquoi les programmeurs continuent de le demander. Mais cela ne correspondait pas tout à fait à la façon dont les concepteurs pensaient la langue.
Comme il n'est pas disponible, j'ai pris l'habitude d'utiliser des méthodes non statiques de la manière indiquée ci-dessous. Pas exactement idéal, mais je ne vois aucune approche plus logique, du moins pas pour moi.
la source
Donc, si vous voulez accéder aux méthodes du contrat d'interface, vous devez créer un objet. Il faut toujours que ce ne soit pas autorisé dans le cas des méthodes statiques. Les classes, méthodes et variables statiques ne nécessitent jamais d'objets et ne se chargent pas en mémoire sans créer d'objet de cette zone (ou classe) ou vous pouvez dire ne nécessitent pas de création d'objet.
la source
Conceptuellement il n'y a aucune raison pour qu'une interface ne puisse pas définir un contrat incluant des méthodes statiques.
Pour l'implémentation actuelle du langage C #, la restriction est due à la tolérance d'héritage d'une classe de base et des interfaces. Si "classe SomeBaseClass" implémente "interface ISomeInterface" et "classe SomeDerivedClass: SomeBaseClass, ISomeInterface" implémente également l'interface, une méthode statique pour implémenter une méthode d'interface échouera à la compilation car une méthode statique ne peut pas avoir la même signature qu'une méthode d'instance (ce qui être présent dans la classe de base pour implémenter l'interface).
Une classe statique est fonctionnellement identique à un singleton et sert le même objectif qu'un singleton avec une syntaxe plus propre. Puisqu'un singleton peut implémenter une interface, les implémentations d'interfaces par statique sont conceptuellement valides.
Donc, cela se résume simplement à la limitation des conflits de noms C # par exemple et aux méthodes statiques du même nom à travers l'héritage. Il n'y a aucune raison pour que C # ne puisse pas être «mis à niveau» pour prendre en charge les contrats de méthode statique (interfaces).
la source
Lorsqu'une classe implémente une interface, elle crée une instance pour les membres de l'interface. Alors qu'un type statique n'a pas d'instance, il n'y a aucun intérêt à avoir des signatures statiques dans une interface.
la source