web-dev-qa-db-fra.com

Avoir une fonction héritée renvoie le type dérivé au lieu du type de base

J'écris deux classes en C #:

  • Une classe Matrix représentant une matrice générale avec des dimensions N-BY-M
  • Une classe SquareMatrix qui hérite de Matrix et a la contrainte d'être N-by-N

La raison pour laquelle je l'ai conçue de cette façon est que des matrices carrées prennent en charge des opérations spécifiques supplémentaires telles que le calcul du déterminant ou de l'inverse, de sorte de garanifier que ces fonctions sont disponibles avec le type spécifique que vous utilisez sont de belles choses à utiliser. En outre, il prendrait en charge toutes les opérations matricielles ordinaires et peut être utilisée comme matrice

J'ai une fonction dans Matrix appelé getTranspose(). Il calcule la transposition de la matrice et le renvoie comme un nouveau Matrix

Je hérite de le hériter dans SquareMatrix, mais parce que la transposition d'une matrice carrée est garantie pour être une matrice carrée, je veux aussi qu'il retourne un SquareMatrix

Je ne suis pas sûr de la meilleure façon de le faire.

  • Je peux ré-implémenter la fonction dans SquareMatrix, mais ce serait une duplication de code parce que c'est essentiellement le même calcul
  • Je peux utiliser des opérateurs de typast implicites, mais si je comprends correctement, cela entraînerait des allocations inutiles (Upcast SquareMatrix à Matrix, créez une nouvelle Matrix comme transposez, créez une nouvelle SquareMatrix lors de la typée et jetez les tranches Matrix)
  • Je peux utiliser des opérateurs de tycast explicites, mais il serait stupide de devoir taper la transposition d'un SquareMatrix explicitement, et il a également le même problème de l'opérateur implicite avec des allocations inutiles

Y a-t-il une autre option? Devrais-je changer la conception d'avoir SquareMatrix hériter de Matrix?

Ce problème s'applique également aux opérateurs. Il semble que je dois soit implémenter des opérateurs de caractères de texte qui pourraient coûter en performance, ou avoir à ré-implémenter le même code.

6
9a3eedi

Le problème est que le concept de "ce type" manque au C #. Il peut être simulé mais il utilise une syntaxe un peu complexe ou déroutant, et je ne conseillerais pas l'utiliser. La question ci-dessous décrit une telle mise en œuvre.

https://stackoverflow.com/questions/1400831/is-it-possible-à-Make-Ce-type-for-généric-in-c

2
Florian F

Utilisez l'opérateur "Nouveau" dans la fonction héritée pour remplacer la sortie et appeler la classe de base à l'aide de l'opérateur "Base".

Quelque chose comme:

public new SquareMatrix getTranspose()
{
    // Do something different here... or not...
    return (SquareMatrix)base.getTranspose();
}
2
Alan Ahlberg

La pénalité de performance pour la coulée que vous suggérez n'est pas réelle, rien n'est réaffecté si vous lancez un type de base à un type dérivé. Vous pouvez donc le faire en toute sécurité sur les destinataires. Si le code client sait qu'il obtiendra un type plus riche, car il a créé la classe dérivée, elle peut lancer le type retourné au type plus riche, de préférence en utilisant l'opérateur "comme". Ce n'est pas du tout mal pratique.

Si vous êtes vraiment bugié par le Cast In Code client, vous pouvez ajouter une méthode supplémentaire dans la classe dérivée (avec un nom légèrement différent). Vous n'avez pas besoin de réimplémenter quoi que ce soit comme vous le suggérez, vous appelleriez la base.getTransposez et faites la distribution avant le retour.

Les génériques n'entraîneraient pas beaucoup ici car le type T devrait être la classe mise en œuvre plutôt que sur un type de variante qui y est manipulé. C'est impossible.

La suggestion d'Alan est un piratage, il tuerait la virtualité de la méthode de descendants.

Mais voici le kicker: votre idée d'utiliser une classe dérivée pour mettre en œuvre une contrainte est fausse. Il viole le LSP et est la cause première de votre problème même. Vous devriez simplement avoir une propriété Issquare à la place de votre classe de base.

1
Martin Maat