2009-02-06 7 views
6

Voici une version simplifiée de ma classe:Une classe de base peut-elle déterminer si une classe dérivée a remplacé un membre virtuel?

public abstract class Task 
{ 
    private static object LockObject = new object(); 

    protected virtual void UpdateSharedData() { } 
    protected virtual void UpdateNonSharedData() { } 

    public void Method() 
    { 
     lock(LockObject) 
     { 
      UpdateSharedData(); 
     } 
     UpdateNonSharedData(); 
    } 
} 

J'essaie de cacher le code de verrouillage des classes dérivées. Mais je veux seulement obtenir le verrou si la classe dérivée remplace OverSharedData; Si ce n'est pas le cas, je ne veux pas que la méthode bloque et attende toutes les autres instances en cours d'exécution qui mettent à jour les données partagées avant de mettre à jour les données non partagées. Donc, la chose (apparemment) évidente pour Method à faire est de vérifier et de voir si l'implémentation de UpdateSharedData de l'instance actuelle a surchargé l'implémentation de la classe de base. Je suis assez sûr que ce n'est pas possible sans utiliser la réflexion, et ce n'est probablement pas souhaitable de le faire.

J'ai pensé quelques solutions de contournement à ce sujet, mais ils sont tous assez maladroits:

  • Ajouter une propriété bool protégée que les ensembles de constructeur de la classe dérivée, et vérifiez que la propriété pour voir si un verrou est nécessaire. Cela fait un travail terrible de cacher le code de verrouillage des classes dérivées.
  • Affectez à la méthode UpdateSharedData une propriété de délégué, avez une classe dérivée définir la propriété à une méthode privée dans son constructeur et n'obtenez le verrou que si le délégué n'est pas null. C'est mieux, mais ça craint quand même.

Répondre

4

si vous avez défini une tâche abstraite et une interface IHasSharedData, puis dans la méthode que vous vérifier si le groupe dérivé implémente IHasSharedData avant de faire la fermer à clé. Seules les classes implémentant l'interface doivent attendre. Je réalise que cela évite de répondre à la question, mais je pense que ce serait une solution plus propre que d'utiliser la réflexion. Heureusement, vous trouverez un meilleur nom pour l'interface qui correspond mieux à ce que les classes font réellement.

public interface IHasSharedData 
{ 
    void UpdateSharedData(); 
} 

public abstract class Task 
{ 
    private static object LockObject = new object(); 

    protected virtual void UpdateNonSharedData() { } 

    public void Method() 
    { 
     if (this is IHasSharedData) 
     { 
      lock(LockObject) 
      { 
       UpdateSharedData(); 
      } 
     } 
     UpdateNonSharedData(); 
    } 
} 

public class SharedDataTask : Task, IHasSharedData 
{ 
    public void UpdateSharedData() 
    { 
     ... 
    } 
} 
+0

Je viens de réaliser que IHasSharedData ressemble beaucoup au code LOLCats. :-) ICanHazSharedData? – tvanfosson

+0

C'était la première chose que j'ai remarquée aussi! Ça va être très difficile pour moi de résister à l'idée de lui donner un nom comme ça. C'est exactement la réponse que je cherchais néanmoins. –

4

Vous pouvez faire cette vérification avec un smidge de réflexion:

bool IsUpdateSharedDataOverridden() 
{ 
    Type t = this.GetType(); 
    MethodInfo m = subType.GetMethod("UpdateSharedData"); 

    return m.DeclaringType == t && m.GetBaseDefinition().DeclaringType == typeof(Task); 
} 
+0

Il serait plus correct de comparer m.DeclaringType directement à t. Il est très possible que deux types différents aient le même nom. – JaredPar

+0

Cela indiquerait également vrai si elle utilisait "new" pour re-déclarer (pas surcharger) la méthode. –

+0

Bons points. Fixé en conséquence. –

0

En fait, vous parlez de deux objets différents:

public abstract class Task {  
    protected virtual void UpdateNonSharedData() { } 

    public virtual void Method()  
    { 
     UpdateNonSharedData();  
    } 
} 

public abstract class TaskWithSharedData : Task {  
    private static object LockObject = new object();  

    protected virtual void UpdateSharedData() { } 

    public overrides void Method()  
    {  
     lock(LockObject) 
     {   
      UpdateSharedData();  
     } 
     base.Method(); 
    } 
} 

Mais, solution plus idéale sera le modèle de stratégie.

Questions connexes