2013-07-22 9 views
5

ho scritto il seguente console app per testare le proprietà statiche:Qual è il modo migliore per definire una proprietà statica che viene definita una volta per sottoclasse?

using System; 

namespace StaticPropertyTest 
{ 
    public abstract class BaseClass 
    { 
     public static int MyProperty { get; set; } 
    } 

    public class DerivedAlpha : BaseClass 
    { 
    } 

    public class DerivedBeta : BaseClass 
    { 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      DerivedBeta.MyProperty = 7; 
      Console.WriteLine(DerivedAlpha.MyProperty); // outputs 7 
     } 
    } 
} 

Come questa console app dimostra, la proprietà MyProperty esiste una volta per tutte le istanze di BaseClass. C'è un modello da usare che mi permetterebbe di definire una proprietà statica che avrà allocata memoria per ogni tipo di sottoclasse?

dato l'esempio di cui sopra, vorrei tutte le istanze di DerivedAlpha di condividere la stessa proprietà statica, e tutte le istanze di DerivedBeta per condividere un'altra istanza della proprietà statica.

Perché sto provando a farlo?

Sto iniziando pigramente una raccolta di nomi di proprietà di classe con determinati attributi (tramite riflessione). I nomi di proprietà saranno identici per ogni istanza di classe derivata, quindi sembra inutile archiviarlo in ogni istanza di classe. Non riesco a renderlo statico nella classe base, perché diverse sottoclassi avranno proprietà diverse.

Non voglio replicare il codice che popola la raccolta (tramite riflessione) in ogni classe derivata. So che una possibile soluzione è definire il metodo per popolare la raccolta nella classe base e chiamarla da ogni classe derivata, ma questa non è la soluzione più elegante.

Aggiornamento - Esempio di quello che sto facendo

Su richiesta di Jon, ecco un esempio di quello che sto cercando di fare. Fondamentalmente, posso opzionalmente decorare le proprietà nelle mie classi con l'attributo [SalesRelationship(SalesRelationshipRule.DoNotInclude)] (ci sono altri attributi, questo è solo un esempio semplificato).

public class BaseEntity 
{ 
    // I want this property to be static but exist once per derived class. 
    public List<string> PropertiesWithDoNotInclude { get; set; } 

    public BaseEntity() 
    { 
     // Code here will populate PropertiesWithDoNotInclude with 
     // all properties in class marked with 
     // SalesRelationshipRule.DoNotInclude. 
     // 
     // I want this code to populate this property to run once per 
     // derived class type, and be stored statically but per class type. 
    } 
} 

public class FooEntity : BaseEntity 
{ 
    [SalesRelationship(SalesRelationshipRule.DoNotInclude)] 
    public int? Property_A { get; set; } 

    public int? Property_B { get; set; } 

    [SalesRelationship(SalesRelationshipRule.DoNotInclude)] 
    public int? Property_C { get; set; } 
} 

public class BarEntity : BaseEntity 
{ 
    public int? Property_D { get; set; } 

    [SalesRelationship(SalesRelationshipRule.DoNotInclude)] 
    public int? Property_E { get; set; } 

    public int? Property_F { get; set; } 
} 

finale desiderato risultato

Accesso FooEntity.PropertiesWithDoNotInclude restituisce una List<string> di:

{ 
    "Property_A", 
    "Property_C" 
} 

Accesso BarEntity.PropertiesWithDoNotInclude restituisce una List<string> di:

{ 
    "Property_E" 
} 

risposta

4

Jon ha una buona soluzione come al solito, anche se non vedo quali sono gli attributi validi qui, poiché devono essere esplicitamente aggiunto a ogni sottotipo e non si comportano come proprietà.

L'approccio può sicuramente funzionare. Ecco un altro modo per farlo, che dichiara esplicitamente che non ci sarà una variabile per sottoclasse di BaseEntity:

class FilteredProperties<T> where T : BaseEntity 
{ 
    static public List<string> Values { get; private set; } 
    // or static public readonly List<string> Values = new List<string>(); 
    static FilteredProperties() 
    { 
     // logic to populate the list goes here 
    } 
} 

Lo svantaggio di questo è che è piuttosto difficile da abbinare con una chiamata GetType() come si potrebbe utilizzare nei metodi di BaseEntity. A Dictionary, o wrapper che implementa la popolazione pigra, è meglio per tale utilizzo.

+0

L'OP ha specificato che "I nomi delle proprietà saranno identici per ogni istanza di classe derivata" - il che suggerisce che è effettivamente una costante per ogni classe, il che significa che può essere un attributo che viene poi recuperato per riflessione. No, non si comporta esattamente come una proprietà - ma ti permette di specificare un valore per classe e poi di recuperare quel valore ... Ora abbiamo più informazioni nella domanda, è più chiaro ciò che l'OP sta cercando di fare, e un dizionario da 'Tipo' a * qualcosa * è probabilmente la strada da percorrere. –

+0

La tua soluzione intende utilizzare un approccio singleton (per tipo di argomento)? Se è così, mi piace - ma si potrebbe fare con l'espansione un po '. –

+0

@Jon: oops Ho perso una parola chiave 'static'. –

3

Due possibili approcci:

  • Utilizzare attributi; decorare ciascuna sottoclasse con un attributo, ad es.

    [MyProperty(5)] 
    public class DerivedAlpha 
    { 
    } 
    
    [MyProperty(10)] 
    public class DerivedBeta 
    { 
    } 
    

    Questo funziona solo quando sono effettivamente costanti, ovviamente.

  • utilizzare un dizionario:

    var properties = new Dictionary<Type, int> 
    { 
        { typeof(DerivedAlpha), 5) }, 
        { typeof(DerivedBeta), 10) }, 
    }; 
    

EDIT: Ora che abbiamo più contesto, la risposta di Ben è davvero un buon uno, con il modo in cui funzionano i farmaci generici in C#.È come l'esempio del dizionario, ma con la pigrizia, la sicurezza dei thread e l'accesso globale semplice tutto integrato.

+0

Ho ampliato la mia risposta. – LeopardSkinPillBoxHat

+0

Nel tuo secondo esempio, intendevi "DerivatoBeta' per il secondo elemento? :) –

+0

@ Chips_100: corretto, grazie. –

0

Risposta uno:
sovrascrivere la struttura in ogni classe utilizzando new int

public abstract class BaseClass 
{ 
    public static int MyProperty { get; set; } 
} 

public class DerivedAlpha : BaseClass 
{ 
    public static new int MyProperty { get; set; } // !! new int !! 
} 

public class DerivedBeta : BaseClass 
{ 
    public static new int MyProperty { get; set; } // !! new int !! 
} 

     DerivedAlpha.MyProperty = 7; 
     DerivedBeta.MyProperty = 8; 
     BaseClass.MyProperty = 9; 

Risposta due:
valori Mettere in un dizionario per ogni tipo

public abstract class BaseClass2<T> 
{ 
    public static Dictionary<Type, int> propertyStore = new Dictionary<Type, int>(); 

    public static int MyProperty 
    { 
     get 
     { 
      var t = typeof(T); 
      return propertyStore[t]; 
     } 

     set 
     { 
      var t = typeof(T); 
      propertyStore[t] = value; 
     } 
    } 
} 

public class DerivedAlpha2 : BaseClass2<DerivedAlpha2> 
{ 
} 

public class DerivedBeta2 : BaseClass2<DerivedBeta2> 
{ 
} 

     DerivedBeta2.MyProperty = 7; 
     DerivedAlpha2.MyProperty = 8; 
     // BaseClass2.MyProperty = 9; // does not compile 
Problemi correlati