2009-07-14 5 views
0

J'ai besoin de créer une classe de base comme le code suivant.Est-il possible de créer un champ statique sur la classe de base mais affecter comme créer sur la classe enfant?

public class ResourceBase 
{ 
    protected static IDictionary<string, XDocument> resources; 

    protected static IDictionary<string, XDocument> Resources 
    { 
     get 
     { 
      if (resources == null) 
      { 
       // cache XDocument instance in resources variable seperate by culture name. 
       // load resx file to XDocument 
      } 

      return resources;     
     } 
    } 

    protected static string GetString(string resourceKey) 
    { 
     return GetString(resourceKey, System.Threading.Thread.CurrentThread.CurrentUICulture.Name); 
    } 

    protected static string GetString(string resourceKey, string cultureName) 
    { 
     // get data from XDocument instance 
     var result = (
         from rs in Resources 
         let node = rs.Value.Root.Elements(XName.Get("data")).SingleOrDefault<XElement>(x => x.Attribute(XName.Get("name")).Value == resourceKey) 
         where 
           (rs.Key == DEFAULT_CULTUREKEY || cultureName == rs.Key) && 
           node != null 
         orderby cultureName == rs.Key descending 
         select node.Element(XName.Get("value")) 
        ).FirstOrDefault<XElement>(); 

     return result.Value; 
    } 
} 

Ensuite, je crée une classe enfant comme le code suivant.

public class MainResource : ResourceBase 
{ 
    public static string AppName 
    { 
     return GetString("AppName"); 
    } 
} 

public class OtherResource : ResourceBase 
{ 
    public static string OtherName 
    { 
     return GetString("OtherName"); 
    } 
} 

J'ai un problème parce que la variable de ressource dans la classe de base. Toutes les classes enfant utilisent une variable Ressource. Ainsi, ils utilisent toujours la même instance XDocument en cache. Avez-vous une idée pour réparer mon code source?

PS. J'ai trouvé un attribut comme ContextStaticAttribute qui indique que la valeur d'un champ statique est unique pour un contexte particulier. Je pense un contexte particulier devrait être le fil de différence. Donc, je ne peux pas l'utiliser pour résoudre cette question.

Merci,

+0

Alors, quel est le problème? Que MainResource et OtherResource ne doivent pas partager des informations de ressources mises en cache? Vous pouvez passer un nom de fichier via le constructeur et ne pas utiliser d'implémentations statiques. – sisve

+0

Je dois utiliser une variable statique car il est facile de partager une variable pour un projet multi-tiers sans se préoccuper de l'initialisation, de la mise en cache ou des performances. –

Répondre

0

2.La solution la plus simple pour résoudre ce problème en utilisant uniquement l'extension de méthode.

fichier de ressources fortement typé

[ResourceInfo("~/Views/Home", "Index")] 
public class IndexView 
{ 
    protected static IDictionary<string, XDocument> resources = new Dictionary<string, XDocument>(); 

    public static string Title 
    { 
     get 
     { 
      return resources.GetString("Title"); 
     } 
    } 
} 

fichier Aide Resource

public static class ResourceHelper 
{ 
    const string RESOURCE_EXTENSION = "resx"; 
    const string DEFAULT_CULTUREKEY = "(default)"; 

    public static string GetString(this IDictionary<string, XDocument> resource, string resourceKey) 
    { 
     return resource.GetString(resourceKey, System.Threading.Thread.CurrentThread.CurrentUICulture.Name); 
    } 

    public static string GetString(this IDictionary<string, XDocument> resource, string resourceKey, string cultureName) 
    { 
     if (resource.Count == 0) 
      resource.LoadResource(); 

     // retrieve data 
    } 

    public static void LoadResource(this IDictionary<string, XDocument> resource) 
    { 
     // logic to load resource 
    } 

Je l'ai testé avec cette logique même cas de test comme # solution1. Mais j'ai trouvé un résultat très intéressant. Il peut récupérer plus de 120 000 opérations/s. Donc, c'est ma réponse finale parce que c'est simplement, propre et rapide.

Merci,

3

Faire la classe de base abstraite et ne fournissent pas une mise en œuvre des ressources. La classe dérivée peut alors fournir sa propre ressource à la méthode GetString de la classe de base.

+0

Ça ne marche pas! Parce qu'il cache toujours XDocument de la première classe enfant appelée. –

+0

vous avez déplacé les ressources, mais pas le getter. Vous devez déplacer le getter à la classe enfant – Robert

+0

Ce n'est pas mon exigence. Parce que j'ai besoin de partager la logique dans la classe de base seulement et les classes dérivées ont seulement des propriétés pour obtenir la valeur de la ressource. –

3

Cela semble appeler une implémentation Singleton. La raison de votre classe de base est de partager la logique, correct? Au lieu de tout rendre statique, implémentez le modèle Singleton de sorte que chacune de vos classes enfant ait sa propre instance, toutes partageant la logique de votre classe de base. Cela leur permettra d'avoir une mise en cache indépendante tout en partageant la logique de comportement.

+0

Mais il est impossible d'obtenir la valeur des ressources de la classe enfant. De plus, je ne peux pas utiliser le mot-clé "abstract" pour un champ ou une propriété statique. –

+0

Vous devriez faire une recherche google rapide sur Singleton, ou simplement rechercher ce site. Sauf si vous avez besoin d'utiliser des méthodes statiques pour tout faire, alors vous devriez être bon. –

0

Il semble que vous ayez besoin de mettre en cache à chaque fois pour vos classes enfants. Lorsque vous mettez en cache XDocument, vous devez fournir une clé différente pour vos classes enfants. Vous pouvez ajouter à votre classe de base

abstract string ResourceName { get; }; 
protected static IDictionary<string, XDocument> Resources 
{ 
    get 
    { 
     if (resources == null) 
     { 
      //Cache the XDocument with a key based on ResourceName. 
     } 

     return resources;     
    } 
} 

Et puis votre MainResource a

string ResourceName { get { return "AppName"; } } 

public static string AppName 
{ 
    return GetString(ResourceName); 
} 
+0

Mais j'ai beaucoup de noms de ressources et ça ne marche pas. Parce qu'il utilise toujours la même instance de ressource. –

+0

Vous devrez poster votre code qui fait la mise en cache. –

0

1.Solution pour résoudre ce problème en utilisant la variable des ressources statiques pour la mise en cache toutes ressources dépendent du type de classe enfant . Par ailleurs, cette solution nécessite le type de classe enfant à chaque fois en utilisant le code suivant quand j'obtiens la valeur de la ressource. En outre, j'ai testé cette solution environ 10k - 100k tours et il peut récupérer des données sur 6 000 opérations/sec.. Donc, je ne peux pas utiliser cette solution pour une application réelle car chaque requête web doit récupérer plus de 50 opérations.

public static Type GetCallerType(Type baseClass, int skipFrames) 
{ 
    StackTrace trace = new StackTrace(skipFrames + 1, false); 
    Type callerType = null; 

    for (int i = 0; i < trace.FrameCount; ++i) 
    { 
     StackFrame frame = trace.GetFrame(i); 
     Type type = frame.GetMethod().DeclaringType; 

     if (type == baseClass || IsInheritFrom(type, baseClass)) 
     { 
      callerType = type; 
     } 
     else 
     { 
      break; 
     } 
    } 

    if (callerType != baseClass) 
     return callerType; 
    else 
     return null; 
} 
Questions connexes