Question

J'ai récemment rencontré un problème pour lequel j'ai apparemment besoin d'une méthode 'abstraite statique'. Je sais pourquoi c'est impossible, mais comment puis-je contourner cette limitation?

Par exemple, j'ai une classe abstraite qui a une chaîne de description. Étant donné que cette chaîne est commune à toutes les instances, elle est marquée comme statique, mais je veux exiger que toutes les classes dérivées de cette classe fournissent leur propre propriété Description. Je l'ai donc marquée comme abstraite:

abstract class AbstractBase
{
    ...
    public static abstract string Description{get;}
    ...
}

Cela ne se compilera pas, bien sûr. J'ai pensé utiliser des interfaces, mais celles-ci ne peuvent pas contenir de signatures de méthodes statiques.

Devrais-je le rendre simplement non statique, et toujours obtenir une instance pour obtenir cette information spécifique à la classe?

Des idées?

Était-ce utile?

La solution

La combinaison de statique et d’abstrait n’a pas de sens, oui. L'idée derrière static est qu'il n'est pas nécessaire de présenter une instance de la classe pour utiliser le membre en question; Cependant, avec abstract, on s'attend à ce qu'une instance soit une classe dérivée fournissant une implémentation concrète.

Je peux voir pourquoi vous voudriez ce type de combinaison, mais le fait est que le seul effet serait de refuser l'utilisation de "this" ou de tout membre non statique à la mise en oeuvre. C'est-à-dire que la classe mère dicterait une restriction dans l'implémentation de la classe dérivée, même s'il n'y a aucune différence sous-jacente entre l'appel d'un membre abstrait ou 'membre abstrait statique' (dans la mesure où les deux auraient besoin d'une instance concrète pour déterminer quelle implémentation utiliser).

Autres conseils

Vous ne pouvez pas.

Pour ce faire, vous devez utiliser les attributs.

Par exemple

[Name("FooClass")]
class Foo
{
}

Si cela ne vous dérange pas de passer aux implémentations pour implémenter judicieusement la propriété Description, vous pouvez simplement le faire

.
public abstract string ClassDescription {get; } 
// ClassDescription is more intention-revealing than Description

Et l'implémentation des classes ferait quelque chose comme ceci:

static string classDescription="My Description for this class";
override string  ClassDescription { get { return classDescription; } }

Ensuite, vos cours sont tenus de respecter le contrat de description, mais vous leur laissez le soin de le faire avec discernement. Il n'y a aucun moyen de spécifier une implémentation de manière orientée objet (sauf par des piratages cruels et fragiles).

Cependant, dans mon esprit, cette description est une métadonnée de classe. Je préférerais donc utiliser le mécanisme d'attribut comme d'autres l'ont décrit. Si vous êtes particulièrement préoccupé par les utilisations multiples de la réflexion, créez un objet qui reflète l'attribut qui vous intéresse et stockez un dictionnaire entre le type et la description. Cela minimisera la réflexion (autre que l'inspection de type à l'exécution, qui n'est pas si mauvaise). Le dictionnaire peut être stocké en tant que membre de la classe qui a généralement besoin de ces informations ou, si les clients du domaine en ont besoin, via un singleton ou un objet de contexte.

Si c'est statique, il n'y a qu'une seule instance de la variable, je ne vois pas en quoi un héritage aurait un sens si nous pouvions faire ce que vous voulez accomplir avec des vars statiques dans des classes dérivées. Personnellement, je pense que vous allez trop loin pour essayer d'éviter une instance var.

Pourquoi ne pas simplement la manière classique?

abstract class AbstractBase
{
    protected string _Description = "I am boring abstract default value";
}

class Foo : AbstractBase {

     public Foo() {
       _Description = "I am foo!";
     }
}

Ce n'est pas statique s'il doit être appelé sur une instance.

Si vous n'appelez pas cette instance sur une instance, aucun polymorphisme n'est en jeu (par exemple, ChildA.Description n'a aucun lien avec ChildB.Description en ce qui concerne le langage).

Une solution possible consiste à définir un singleton de votre classe dérivée dans votre classe de base à l'aide de Generics.

import System;

public abstract class AbstractBase<T>
    where T : AbstractBase<T>, new()
{
    private static T _instance = new T();

    public abstract string Description { get; }
    public static string GetDescription()
    {
        return _instance.Description;
    }
}

public class DerivedClass : AbstractBase<DerivedClass>
{
    public override string Description => "This is the derived Class";
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(DerivedClass.GetDescription());
        Console.ReadKey();
    }
}

L'astuce consiste à donner à votre AbstractBase<T> quelques détails sur la manière dont DerivedClass est implémenté:

  • Il est possible de le créer avec where T: new() pour pouvoir créer une instance Singleton
  • Il dérive de lui-même avec where T : AbstractBase<T> afin qu'il sache qu'il y aura une implémentation de Description

De cette façon, _instance contient le champ GetDescription() pouvant être appelé dans la méthode statique DerivedClass.GetDescription(). Cela vous oblige à écraser <=> dans votre <=> et vous permet d'appeler sa valeur avec <=>

Vous pouvez créer le " abstract " La méthode de base jette un Exception, donc un développeur est & "averti &"; s'il essaie d'invoquer cette méthode sur une classe enfant sans le redéfinir.

L'inconvénient est que l'on peut étendre la classe sans utiliser cette méthode. Ensuite, reportez-vous aux autres réponses fournies.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top