7
votes

Comment puis-je forcer toutes les classes dérivées à mettre en œuvre une méthode ou une propriété abstraite?

Une fonction abstraite doit être mise en œuvre par toutes les classes en béton.

Parfois, vous souhaitez forcer toutes les classes dérivées à mettre en œuvre la fonction abstraite, même dérivées de classes en béton. P>

class Base { protected abstract Base Clone(); }
class Concrete : Base { protected override Base Clone(){...}; }
class Custom : Concrete {}


3 commentaires

Tant que certaines classes concrètes dans l'arbre d'héritage ont mis en place la méthode abstraite, pourquoi voudriez-vous vous soucier de si un enfant de cette classe concret repose sur la mise en œuvre de son parent?


Je suis en retard à la fête mais j'ai le même problème. J'aimerais avoir un qualificatif abstrait privé qui oblige chaque classe dérivée à mettre en œuvre la fonction, mais empêche le code de la Classe de revenir implicitement à la mise en œuvre d'une classe mère. Clone () est un bon exemple. Mon cas ressemble plus à Tostring () . Quelque chose de générique mais distinct par classe.


En fait, cela doit se produire plus souvent (ou je manque quelque chose).


6 Réponses :


12
votes

Ce n'est pas possible pour le compilateur de l'appliquer. Vous pouvez regarder écrire votre propre plugin d'analyse à gendarme ou FXCop pour appliquer de telles exigences.


2 commentaires

Comment le plugin distingue-t-il la distinction entre le cas où vous souhaitez forcer l'exigence sur tous les dérivés ou simplement les immédiats?


Un attribut serait l'approche la plus simple - [MUSTIMPLEMENT] ou quelque chose de similaire.



2
votes

Vous devrez faire concret une classe abstraite pour appliquer cela.


1 commentaires

L'objectif est d'avoir une classe de base facile à prolonger. Vous n'avez pas de contrôle sur la façon dont les gens vont prolonger votre classe. Vous ne pouvez même pas être autour. Le premier prix consiste à documenter l'exigence du code que le compilateur peut appliquer.



0
votes

Vous pouvez vérifier cela au moment de l'exécution à l'aide de la réflexion et lancez une exception pour perturber l'exécution, détruisant des utilisateurs «impolit» de votre bibliothèque. Performance-sage qui n'est pas très sage, même si vous pouviez stocker un hashset dans la classe abstraite de base avec tous les types vérifiés.

Je pense que votre meilleur pari est de fournir une documentation claire qui indique à n'importe quel utilisateur de votre code qu'il est jugé nécessaire de remplacer la méthode clone ().


0 commentaires

3
votes

Je suppose que vous n'avez pas besoin de toutes les classes dérivées pour mettre en œuvre la méthode abstraite, mais cela sonne certainement comme si vous avez un peu une odeur de code dans votre conception.

Si vous n'avez pas de fonctionnalité La méthode Concrete.clone (), vous pouvez également rendre votre résumé de classe «concrets» également (assurez-vous simplement de changer le nom ;-). Laissez toute référence de la méthode clone (). P> xxx pré>

si vous avez une fonctionnalité de base dans la méthode concret.clone (), mais avez besoin d'informations détaillées d'un niveau supérieur, Ensuite, cédez-la dans sa propre méthode abstraite ou une propriété forçant une implémentation de niveau supérieur pour fournir ces informations. P>

abstract class Base { protected abstract void Clone(); }

abstract class ConcreteForDatabases : Base 
{ 
    protected abstract string CopyInsertStatemement {get;}

    protected override void Clone()
    {
        // setup db connection & command objects
        string sql = CopyInsertStatemement;
        // process the statement
        // clean up db objects
    }
}

class CustomBusinessThingy : ConcreteForDatabases 
{
    protected override string CopyInsertStatemement {get{return "insert myTable(...) select ... from myTable where ...";}}
}


1 commentaires

J'ai corrigé mes exemples de méthodes de clone pour retourner la base. Lorsque vous implémentez le clonage d'objet à l'aide de méthodes de clone virtuel, vous devez avoir toutes les classes dérivées pour mettre en œuvre la méthode abstraite.



-2
votes

Supprimer la mise en œuvre en classe de béton ou utilisez la classe de base


0 commentaires

0
votes

J'ai fait le test Nunit suivant qui utilise la réflexion pour vérifier la mise en œuvre. J'espère que vous pourrez vous adapter au besoin.

Je soupçonne que cela ne gérera pas de méthodes surchargées bien, mais c'est suffisant pour ce que je veux. P>

(Commentaires Bienvenue) P>

    public static bool HasAttributeOfType<T>(this ICustomAttributeProvider provider)
    {
        return provider.GetCustomAttributes(typeof(T), false).Length > 0;
    }

    public static IEnumerable<Type> ThisTypeAndSubClasses(this Type startingType)
    {
        var types = new List<Type>();
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            try
            {
                foreach (var type in assembly.GetTypes())
                {
                    if (startingType.IsAssignableFrom(type))
                    {
                        types.Add(type);
                    }
                }
            }
            catch (ReflectionTypeLoadException)
            {
                // Some assembly types are unable to be loaded when running as nunit tests.
                // Move on to the next assembly
            }
        }
        return types;
    }


0 commentaires