2009-09-01 15 views
4

je la situation suivante dans le code, que je soupçonne peut-être un peu dodgey:Accès méthodes statiques sur une classe générique dans C#

J'ai une classe:

abstract class DataAccessBase<T> : IDataAccess where T : AnotherAbstractClass 

Cette classe DataAccessBase a également une méthode de fabrication statique qui crée des instances de classes dérivées de lui-même à l'aide d'une valeur ENUM dans une déclaration qui à décider quel dérivé de type à créer:

static IDataAccess CreateInstance(TypeToCreateEnum) 

maintenant, la ty pes dérivés de DataAccessBase<T> sont eux-mêmes pas générique, ils précisent un type T:

class PoLcZoneData : DataAccessBase<PoLcZone> // PoLcZone is derived from AnotherAbstractClass 

Jusqu'à présent, je ne suis pas sûr que ce soit repousser les limites de bon usage des médicaments génériques, mais ce que je suis vraiment préoccupé par comment pour accéder à la méthode statique CreateInstance() en premier lieu:

La façon dont je fais cela en ce moment est de simplement passer tout type T où T: AnotherAbstractClass. En particulier je passe AnotherAbstractClass lui-même. Cela permet une bonne compilation, mais il me semble que passer n'importe quel type à une classe générique juste pour avoir de la statique est un peu douteux.

J'ai fait simplifié la situation un peu comme DataAccessBase<T> est le niveau inférieur dans la chaîne d'héritage, mais les méthodes d'usine statique existe dans un niveau intermédiaire avec des classes telles que PoLcZoneData étant les plus dérivées sur le seul niveau qui n'est pas générique.

Que pensent les gens de cet arrangement?

+0

Quelle langue est-ce? –

+0

Je suis désolé, son C#. J'ai oublié d'ajouter ça au titre. – MrLane

Répondre

9

Vous êtes autorisé à avoir une classe non générique du même nom ... peut-être quelque chose comme:

abstract class DataAccessBase<T> : IDataAccess where T : AnotherAbstractClass 
{ 
    ... 
} 
static class DataAccessBase 
{ 
    public static IDataAccess CreateInstance(TypeToCreateEnum) {...} 
} 

Maintenant, vous pouvez utiliser DataAccessBase.CreateInstance sans T redondant. En général, vous pouvez appeler internal méthodes sur DataAccessBase<T> à partir de DataAccessBase - bien que je soupçonne dans votre scénario que vous pourriez également avoir besoin d'un peu de réflexion/MakeGenericType.

0

Je ne pense pas qu'il y ait quelque chose de mal avec cette conception, spécialement si vous utilisez le paramètre template pour spécifier un détail d'implémentation. Ce que je suggérerais serait simplement que la fonction d'usine ne soit pas statique, mais seulement autonome. Ce serait la manière la plus claire de s'y prendre pour moi.

Si vous voulez l'encapsuler d'une certaine manière je suggérerais alors un espace de nom, ou une convention de nommage.

Une autre solution serait tout simplement cacher ce que vous faites actuellement, en définissant un type de DataAccessBase peut-être comme ceci:

typedef DataAccessBase<AnotherAbstractClass> DataAccessBaseFactory; 

Ceci est ma solution la moins recommandée, mais il laisse la fonction Créer comme statique si vous le voulez absolument.

+0

@killerfox C'est C# –

+0

Ok, dans ce cas je suppose que la seule option est d'encapsuler la fonction d'usine dans une classe séparée au lieu d'un espace de noms –

2

J'ai déjà rencontré un problème similaire ("comment surcharger des méthodes statiques") et je l'ai résolu avec Reflection.

Voilà ma situation:

1) public abstract class AuditObject<T> : ActiveRecordBase<T> (oui j'utilise ActiveRecord) et

2) public class Employee : AuditObject<Employee>

Dans les deux je définis des méthodes statiques, par exemple

public static DataTable GetLookupTable(String where, Int32 topRows) 
{ 
    return doExtremelyCleverStuffToFetchData(where, topRows); 
} 

(en # 2 vous avez besoin public **new** static ou bien vous obtenez un avertissement du compilateur) Comme le code est

, quand je l'appelle par exemple

DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100); 

... et T est employé, la méthode statique est pas « surchargée » à-dire celui qui est exécuté est le procédé (1), non (2).

Donc, en (1) Je modifié les méthodes statiques (dans cet exemple, GetLookupTable) comme ceci:

public static DataTable GetLookupTable(String where, Int32 topRows) 
{ 
    DataTable tbl = null; 

    Boolean hasOverride = hasMethodOverride("GetLookupTable"); 

    if (hasOverride) 
    { 
     tbl = invokeStaticMethod<T>(
      "GetLookupTable", new Object[2] { where, topRows }) 
      as DataTable; 
    } 
    else 
    { 
     tbl = doExtremelyCleverStuffToFetchData(where, topRows); 
    } 

    return tbl; 
} 

Voici comment je savoir si la méthode statique existe:

private static Boolean hasMethodOverride(String methodName) 
{ 
    var methodQuery = 
     from method in typeof(T).GetMethods(
      BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod) 
     where method.Name == methodName 
     select method; 

    return methodQuery.Count() > 0; 
} 

Et voici comment la méthode "override" est appelée:

public static Object invokeStaticMethod<T>(String MethodName, Object[] Args) 
{ 
    return typeof(T).InvokeMember(MethodName, 
     BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, 
     null, null, Args); 
} 

Voila! Lorsque j'appelle DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100); et que T est Employé, j'obtiens les résultats de la méthode statique définie dans la classe Employé.

Hope this helps,

Dimitris

Questions connexes