C#, implémenter des méthodes de type 'static abstract'

J'ai récemment rencontré un problème où il semble que j'ai 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. Puisque 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é de Description, Donc je l'ai marquée comme abstraite:

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

Il ne compilera pas bien sûr. J'ai pensé d'utiliser des interfaces mais les interfaces peuvent ne pas contenir de signatures de méthode statiques.

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

Des idées?

38
demandé sur yoozer8 2009-05-05 10:58:41

7 réponses

Combiner statique et abstrait est quelque peu dénué 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 d'une classe dérivée qui fournit une implémentation concrète.

Je peux voir pourquoi vous voudriez ce genre de combinaison, mais le fait est que le seul effet serait de refuser l'utilisation de 'this' ou de tout membre non statique. Qui est le parent de la classe dicter une restriction dans l'implémentation de la classe dérivée, même s'il n'y a pas de différence sous-jacente entre appeler un membre abstrait ou ' abstrait statique '(car les deux auraient besoin d'une instance concrète pour comprendre quelle implémentation utiliser)

5
répondu bdonlan 2009-05-05 07:03:47

Vous ne pouvez pas.

L'endroit pour le faire est avec des attributs.

Par exemple

[Name("FooClass")]
class Foo
{
}
31
répondu leppie 2009-05-05 07:02:10

Si cela ne vous dérange pas de reporter les implémentations pour implémenter raisonnablement la propriété Description, Vous pouvez simplement faire

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

Et implémenter des classes ferait quelque chose comme ceci:

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

Ensuite, vos classes sont tenues de suivre le contrat d'avoir une description, mais vous leur laissez le soin de le faire raisonnablement. Il n'y a aucun moyen de spécifier une implémentation de manière orientée objet (sauf par des hacks cruels et fragiles).

Cependant, dans mon esprit cette Description est-ce que les métadonnées de classe, donc je préférerais 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 sur 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 d'exécution, ce qui n'est pas si mauvais). Le dictionnaire peut être stocké en tant que membre de n'importe quelle classe qui a généralement besoin de cette information, ou, si les clients du domaine l'exigent, via un objet singleton ou context.

6
répondu JasonTrue 2009-05-11 18:20:46

S'il est statique, il n'y a qu'une seule instance de la variable, Je ne vois pas comment l'héritage aurait du sens si nous pouvions faire ce que vous voulez accomplir avec des variables statiques dans les classes dérivées. Personnellement, je pense que vous allez loin pour essayer d'éviter une instance var.

Pourquoi 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!";
     }
}
5
répondu Chad Grant 2009-05-05 07:16:28

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

Si vous ne l'appelez pas sur une instance, il n'y a pas de polymorphisme en jeu (C'est-à-dire ChildA.Description est complètement sans rapport avec ChildB.Description en ce qui concerne la langue).

3
répondu Yuliy 2009-05-05 07:03:00

Une solution de contournement possible consiste à définir un Singleton de votre classe dérivée dans votre classe de base à l'aide de génériques.

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 à indiquer à votre AbstractBase<T> quelques détails sur la façon dont DerivedClass est implémenté:

  • Il est newable avec where T: new() donc il peut créer une instance Singleton
  • il dérive de lui-même avec where T : AbstractBase<T> donc il sait qu'il y aura une implémentation de Description

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

1
répondu Manuel Gschrey 2018-06-10 18:22:52

Vous pouvez faire en sorte que la méthode de base "abstraite" lance un Exception, alors un développeur est "averti" s'il essaie d'invoquer cette méthode sur une classe enfant sans surcharger.

L'inconvénient est que l'on peut étendre la classe et ne pas utiliser cette méthode. Reportez-vous ensuite aux autres réponses fournies.

0
répondu Wojciech 2014-04-09 19:56:17