2009-10-30 15 views
25

Il titolo potrebbe essere un po 'ambiguo, ma non riuscivo a pensare a un modo migliore per esprimerlo.Modifica dei valori dei parametri prima dell'invio al costruttore di base

Mi rendo conto che non posso chiamare un costruttore derivato prima di chiamare un costruttore di base, ma posso in qualche modo modificare/creare i valori dei parametri prima di passarli alla base?

Ad esempio,

public enum InputType 
{ 
    Number = 1, 
    String = 2, 
    Date = 3 
} 

public class BaseClass 
{ 
    public BaseClass(InputType t) 
    { 
     // Logic 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    public DerivedClass(int i) 
     : base(value) 
    // Can I do something to infer what value should be here? 
    { 
     // Logic 
    } 
} 

Se ho una classe derivata che può dedurre il valore desiderato per il costruttore di base (in questo esempio, InputType.Number sarebbe valido per un int,) c'è un modo per modificare e/o creare valori che vengono passati al costruttore base prima dell'esecuzione del costruttore derivato?

risposta

37

Mi aspetto che si possano chiamare metodi statici nell'elenco dei parametri del costruttore della classe base.

public class DerivedClass : BaseClass 
{ 
    public DerivedClass(int i) 
     : base(ChooseInputType(i)) 
    { 
    } 

    private static InputType ChooseInputType(int i) 
    { 
     // Logic 
     return InputType.Number; 
    } 
} 
2

Sì. Va bene usare le espressioni normali, che non accedono all'istanza, per manipolare il valore. Per esempio

public DerivedClass(int i) 
    : base((InputType)i) 
{ 
} 
+0

Non è possibile creare "valore" tramite la logica nel costruttore DerivedClass, tuttavia, poiché base (...) viene eseguita per prima. –

+0

@Reed, sì, quello era un errore di battitura. Significa mettere (InputType) i. Risolto – JaredPar

+0

Sì, puoi trasmettere. Ma stava chiedendo un modo per usare la logica per creare valore, cosa che non si può fare. –

0

No.

Il costruttore di base viene eseguito prima di qualsiasi logica nel costruttore DerivedClass, quindi non c'è modo per iniettare logica.

È tuttavia possibile eseguire il costruttore della classe base, quindi impostare le proprietà nella classe base durante il costruttore della classe dervied per modificare i valori.

0

Tu dici

mi rendo conto che non posso chiamare un costruttore derivata prima di chiamare un costruttore di base

Ma poi si mostrano questo codice

public DerivedClass(int i) 
    : base(value) 
{ 
    // Is it possible to set "value" here? 
    // Logic 
} 

Quando quel codice il blocco è inserito nel costruttore della classe base già eseguito. È comunque possibile modificare il valore in un'espressione prima di passarlo al costruttore base (con alcuni vincoli ovvi). Tuttavia, non avrai accesso al "valore" a meno che non sia un input per il costruttore.

+0

Vedi modifica, ho digitato il commento sulla riga sbagliata. Significava digitarlo sotto la chiamata del costruttore base. –

+0

OK, vedo che altri hanno suggerito di poter modificare il valore prima di inviarlo al costruttore base. –

3

È possibile creare un metodo statico sulla classe derivata e mettere la logica ci:

public enum InputType { 
    Number = 1, 
    String = 2, 
    Date = 3 
} 

public class BaseClass { 
    public BaseClass(InputType t) { 
     // Logic 
    } 
} 

public class DerivedClass : BaseClass { 
    public DerivedClass(int i) 
     : base(GetInputType(i)) { 
     // Is it possible to set "value" here? 
     // Logic 
    } 

    private static InputType GetInputType(Int32 parameter) { 
     // Do something with parameter 
     // and return an InputType 

     return (InputType)Enum.Parse(typeof(InputType), parameter); 
    } 
} 
5

è possibile utilizzare un metodo statico per calcolare un valore da passare al costruttore di base.

public class DerivedClass : 
    BaseClass 
{ 
    public 
    DerivedClass(int i) : 
     base(ComputedValue(i)) 
    { 
    } 

    public static InputType 
    ComputedValue(int i) 
    { 
     return InputType.Number; // or any other computation you want here 
    } 
} 
1

Una trucco mettere logica arbitraria base() clausola senza introdurre un metodo statico separato è quello di utilizzare un lambda o delegato anonima. L'espressione all'interno di base() rientra nell'ambito di tutti i parametri del costruttore, quindi è possibile utilizzarli liberamente all'interno del lambda. Per esempio. (diciamo che questo è C# 2.0, quindi non c'è LINQ scrivere una sola-liner per la stessa cosa):

class Base 
{ 
    public Base(int[] xs) {} 
} 

class Derived : Base 
{ 
    public Derived(int first, int last) 
     : base(
      ((Func<int[]>)delegate 
      { 
       List<int> xs = new List<int>(); 
       for (int x = first; x < last; ++x) 
       { 
        xs.Add(x); 
       } 
       return xs.ToArray(); 
      })()) 
    { 
    } 
} 

Tuttavia, vorrei consigliare vivamente contro l'uso nella pratica, perché dal punto di vista leggibilità questo è davvero orribile. Con un metodo statico è necessario passare esplicitamente gli argomenti del costruttore, ma non è come se ne avessi normalmente più di 3-4.

+0

Pavel, c'è un modo per farlo se la classe base prende più di un argomento costruttore? –

+0

È possibile avere un lambda separato per ogni argomento, ma non sarà possibile condividere le variabili tra questi lambda (tranne per gli argomenti del costruttore). –

+0

Grazie Pavel - questo è esattamente il problema che sto cercando di risolvere .. (condividere le variabili tra lambda). Fondamentalmente voglio incapsulare una logica che esegue alcuni calcoli e restituisce tre campi diversi (ma correlati), ognuno dei quali inizializzerà un parametro distinto per il costruttore della classe base. Ho finito per aggirare questo problema tornando all'approccio metodo statico (più leggibile come hai detto tu), restituendo una struct e chiamando il metodo statico una volta per ogni parametro. È hacky, ma ha funzionato, dal momento che per il mio scenario non ci sono effetti collaterali tra le invocazioni del metodo statico –

Problemi correlati