2010-05-04 18 views
6

Per quanto ne so, non è possibile passare parametri a un costruttore statico in C#. Tuttavia ho 2 parametri che ho bisogno di passare e assegnarli a campi statici prima di creare un'istanza di una classe. Come faccio a farlo?Passaggio di parametri statici a una classe

+6

Sarebbe utile se fosse possibile definire "parametro statico" - non è un termine con cui ho familiarità ... –

+0

@Jon: presumo che vogliano passare argomenti in un costruttore statico. Il che non funziona, naturalmente, ma lo vedo in modo tale da voler inizializzare staticamente i campi statici di una classe con i dati passati in fase di runtime. – Joey

+3

@Johannes: La cosa che mi confonde è dove l'OP si aspetterebbe di passare loro * da *. A differenza dei costruttori di istanze, i costruttori statici non vengono "chiamati", ma vengono eseguiti al momento opportuno. Spero che se il PO chiarisca cosa vogliono effettivamente raggiungere, la risposta potrebbe diventare più chiara. –

risposta

6

Questo può essere un invito a ... un metodo di fabbrica!

class Foo 
{ 
    private int bar; 
    private static Foo _foo; 

    private Foo() {} 

    static Foo Create(int initialBar) 
    { 
    _foo = new Foo(); 
    _foo.bar = initialBar; 
    return _foo; 
    } 

    private int quux; 
    public void Fn1() {} 
} 

Si consiglia di mettere un assegno che 'bar' è già inizializzato (o meno) a seconda dei casi.

+1

Cosa non è stato possibile ottenere facendo passare un argomento 'initialBar' a un costruttore di istanze? – LukeH

+0

In questo esempio, niente. Ma risponde alla sua domanda, senza saperne di più sulla sua situazione specifica, è il meglio che potrei fare. – AlfredBr

+0

@AlfredBr: non è possibile accedere al campo istanza _foo formando un metodo statico ed è impossibile accedere al campo statico "bar" da un'istanza di Foo, come prova il codice. Non capisco affatto la tua soluzione. –

2

Suppongo che intendi membri statici di una classe? In questo caso, si può fare questo:

public class MyClass 
{ 
    public static int MyInt = 12; 
    public static MyOtherClass MyOther = new MyOtherClass();  
} 

Quei membri statici sono garantiti per essere istanziati prima di ogni classe viene creata un'istanza.

Se avete bisogno di una logica complessa, farlo in un costruttore statico:

public class MyClass 
{ 
    public static int MyInt; 
    public static MyOtherClass MyOther; 
    static MyClass() 
    { 
     MyInt = 12; 
     MyOther = new MyOtherClass(); 
    } 
} 

Modifica

base alla tua modifica, direi che basta assegnare i valori a ciò che hanno bisogno di essere prima di creare un'istanza della classe, in questo modo:

public class MyClass 
{ 
    public static int MyInt; 
    public static MyOtherClass MyOther; 
} 

// elsewhere in code, before you instantiate MyClass: 
MyClass.MyInt = 12; 
MyClass.MyOther = new MyOtherClass(); 
MyClass myClass = new MyClass(); 

detto questo, questo metodo non fornisce alcuna garanzia che MyInt e MyOther sono impostati prima MyCl il culo è istanziato. Funzionerà, ma richiede disciplina prima di istanziare MyClass.

Un modello alternativo si potrebbe seguire aspetto:

public class MyClass 
{ 
    private static int MyInt; 
    private static MyOtherClass MyOther; 
    private static bool IsStaticInitialized = false; 

    public static InitializeStatic(int myInt, MyOtherClass other) 
    { 
     MyInt = myInt; 
     MyOther = other; 
     IsStaticInitialized = true; 
    } 

    public MyClass() 
    { 
     if(!IsStaticInitialized) 
     { 
      throw new InvalidOperationException("Static Not Initialized"); 
     } 
     // other constructor logic here. 
    } 
} 

// elsewhere in your code: 
MyClass.InitializeStatic(12, new MyOtherClass()); 
MyClass myClass = new MyClass(); 

// alternatiavely: 
MyClass myClass = new MyClass(); // runtime exception. 
+0

questo è il modo per intializzare i campi statici, ma non per passare dati esterni a un costruttore statico, perché almeno in NET 4, il codice del costruttore statico viene eseguito prima di qualsiasi codice del metodo statico e prima di qualsiasi inizializzazione del campo statico. –

+0

il tuo commento non è preciso - "Gli inizializzatori di variabili di campo statici di una classe corrispondono a una sequenza di assegnazioni che vengono eseguite nell'ordine testuale in cui appaiono nella dichiarazione di classe.Se esiste un costruttore statico (Sezione 10.11) nella classe , l'esecuzione degli inizializzatori di campi statici avviene immediatamente prima dell'esecuzione di tale costruttore statico, altrimenti gli inizializzatori di campo statici vengono eseguiti in un tempo dipendente dall'implementazione prima del primo utilizzo di un campo statico di quella classe. " è detto a: https://msdn.microsoft.com/en-us/library/aa645758(v=vs.71).aspx –

4

Non è possibile passare parametri a un costruttore statico, ma è possibile passare parametri alla classe stessa, tramite parametri di tipo generico.

Leggermente pazza questa idea, tuttavia, la butto fuori comunque.

Rendi generica la classe (con un TypeParam che fornirà un tipo di parametro) e applica vincoli generici su di essa (dettagli nell'esempio di codice), quindi ricava un nuovo tipo di parametro, che contiene virtuals che è possibile utilizzare per leggere ciò che vuoi che i valori dei parametri siano.

//base parameter type - provides the 'anchor' for our generic constraint later, 
//as well as a nice, strong-typed access to our param values. 
public class StaticParameterBase 
{ 
    public abstract string ParameterString{ get; } 
    public abstract MyComplexType ParameterComplex { get; } 
} 

//note the use of the new() generic constraint so we know we can confidently create 
//an instance of the type. 
public class MyType<TParameter> where TParameter:StaticParameterBase, new() 
{ 
    //local copies of parameter values. Could also simply cache an instance of 
    //TParameter and wrap around that. 
    private static string ParameterString { get; set; } 
    private static MyComplexType ParameterComplex { get; set; } 

    static MyType() 
    { 
    var myParams = new TParameter(); 
    ParameterString = myParams.ParameterString; 
    ParameterComplex = myParams.ParameterComplex; 
    } 
} 

//e.g, a parameter type could be like this: 
public class MyCustomParameterType : StaticParameterBase 
{ 
    public override string ParameterString { get { return "Hello crazy world!"; } } 
    public override MyComplexType { get { 
     //or wherever this object would actually be obtained from. 
     return new MyComplexType() { /*initializers etc */ }; 
    } 
    } 
} 

//you can also now derive from MyType<>, specialising for your desired parameter type 
//so you can hide the generic bit in the future (there will be limits to this one's 
//usefulness - especially if new constructors are added to MyType<>, as they will 
//have to be mirrored on this type as well). 
public class MyType2 : MyType<MyCustomParameterType> { } 

//then you'd use the type like this: 
public static void main() 
{ 
    var instance = new MyType<MyCustomParameterType>(); 
    //or this: 
    var instance2 = new MyType2(); 
} 

ho considerato una soluzione che impiega tipo di attributi personalizzati si applica a un parametro di tipo, tuttavia questo è facilmente un modo migliore. Tuttavia, ora userai la tua classe sempre con un tipo di parametro generico (a meno che tu non possa usare il trucco derivante + specializzazione) - probabilmente troppo maldestro per i tuoi gusti.

Preferisco anche questo rispetto alle altre soluzioni qui presentate in quanto non richiede la creazione di soluzioni alternative per l'inizializzazione statica. È comunque possibile utilizzare la garanzia di Net di inizializzazione singola.

Una parola di avviso - si dovrebbe rivedere la struttura?

Detto questo - ricordate, però, dal momento che si può solo parametrizzare la statica una volta (o in questo caso, ogni unicamente parametrizzato statica generica) - sarei chiedendomi perché non basta tirare il codice che sta ottenendo i parametri da dare alla statica, e metterlo nel costruttore statico, in primo luogo? In questo modo non devi ricorrere a strani schemi come questo!

+1

WOW! (Sorride, perché ho imparato qualcosa di nuovo!) – AlfredBr

+0

@AlfredBr - cool, potrebbe essere utile un giorno! Sfortunatamente, però, sta arrivando un codice come questo che a volte rende difficile per me accettare alcuni dei miei componenti accettati da chiunque nel mio team tranne che dai programmatori più hardcore! è la vita! –

+0

@AndrasZoltan: la tua soluzione funziona e ha fatto forse il giorno !!! Oggi è il giorno in cui la tua soluzione è utile per me. È pazzesco, come dici tu, ma è un modo per trasferire dati esterni a un costruttore statico. Grazie –

Problemi correlati