2009-12-01 5 views
7

Diciamo che avere una classe con 300 proprietà senza variabili backing, ciascuna di queste proprietà restituisce un decimale/doppia.proprietà C#, è possibile aggirare definendo get senza definire set (nessuna variabile di supporto)?

Esempio:

public decimal MathValue { get; set; } 

Ora è deciso che ognuno di questi valori devono essere arrotondati.

Sto cercando il modo più semplice per refactoring questo senza dover riscrivere tutte quelle proprietà.

Qualcosa, di questo equivalente che funziona davvero: D:

public decimal MathValue { get {return Math.Round(MathValue);} set; } 
+0

Si consiglia di pensare di tornare in questa classe più tardi e ri- scomporre alcune proprietà in classi pulite e pulite in modo da poter evitare un tale caos. – ChaosPandion

+0

lol, completo su esagerazione da parte mia ero solo curioso come si possa andare in giro una cosa del genere :) – Andrew

risposta

5

È possibile creare un nuovo tipo di valore che finge di essere un decimale, ma restituisce il valore arrotondato. Qualcosa di simile a questo:

struct RoundedDecimal 
{ 
    public decimal Value { get; private set; } 

    public RoundedDecimal(decimal value) : this() 
    { 
     this.Value = value; 
    } 

    public static implicit operator decimal(RoundedDecimal d) 
    { 
     return Math.Round(d.Value); 
    } 
} 

Ogni proprietà nella classe deve essere di tipo RoundedDecimal invece di decimal.

+0

Chiamerei questo 'Int96', perché è quello che effettivamente è. –

+0

Questo è un ottimo modo per rimuoverlo senza rompere l'interfaccia. – ChaosPandion

+0

In realtà sarebbe probabilmente meglio se si rendesse pubblico un campo readonly chiamato Value e lo si arrotonda nel costruttore. – ChaosPandion

6

No. Se avete bisogno di qualsiasi logica personalizzata in entrambi i getter o setter, non è possibile utilizzare auto-proprietà.

+0

e non c'è assolutamente alcun modo di rilevante questa logica o una soluzione intorno a questo senza dichiarare una variabile per ciascuno di essi? – Andrew

+0

Un'alternativa sarebbe quella di scrivere una riga di comando util (o preferibilmente usare T4) per generare le tue 300 proprietà per te da qualche altro file/dati. – ConsultUtah

+0

Potresti usare qualcosa come PostSharp per riscrivere le tue proprietà post-compilazione. Probabilmente non ne vale la pena per qualcosa di così banale come quello, comunque. –

0

Ma cosa succede se il cliente non desidera un valore arrotondato? cioè, qualche nuovo codice client imposta un decimale e si aspetta che il valore "esatto" sia tornato?

Se alcuni client necessitano effettivamente dell'uscita della proprietà call da arrotondare, il client deve gestirlo e lasciare la classe da solo.

+0

Bene, in tal caso il risultato può essere lasciato solo :) per quella particolare proprietà ... l'unica cosa che voglio fare è evitare di dichiarare una variabile per ogni proprietà. – Andrew

1

È possibile creare una derivata di questa classe che sovrascrive l'ottiene e restituisce i valori arrotondati. Dovresti quindi modificare la proprietà di base per essere virtuale. Ma questo ti permetterebbe di definire il risultato senza definire il set e usando le proprietà auto.

public class Base 
{ 
    public virtual decimal MathValue { get; set; } 
} 

public class Derived : Base 
{ 
    public override decimal MathValue 
    { 
     get { return Math.Round(base.MathValue); } 
    } 
} 
+0

Come potrebbe essere realizzato? Mi piacerebbe scavalcare i se stessi, se è possibile. Potresti mostrarmi un esempio? – Andrew

+0

Sicuro. Ho anche chiarito che l'intera proprietà deve essere virtuale, non solo il getter. –

+0

L'ereditarietà sembra essere eccessivo per questo. – ChaosPandion

0

Visual Studio usato per avere un "prop" frammento di codice incorporato che genererebbe qualcosa come il seguente codice:

private decimal _MathValue; 

    public decimal MathValue 
    { 
     get { return _MathValue; } 
     set { _MathValue = value; } 
    } 

che si otterrebbe maggior parte della strada per una soluzione completa, ma dal momento che VS 2008 ora genera la versione automatica di proprietà:

public decimal MathValue { get; set; } 

non ho ancora provato questo, ma here is a suggestion for creating your own code snippet to get the VS 2005 version of the "prop" code snippet back:

+0

Sono più interessato a un modo per aggirare il codice piuttosto che a refript manualmente tutto nella classe anche se ho uno snippet che lo fa per me. – Andrew

+0

Ah, sì avrei dovuto leggere la tua domanda più da vicino. Vedo che ti trovi in ​​una situazione in cui hai già definito centinaia di proprietà, quindi questo non ti aiuta davvero tanto. –

+0

:) grazie per l'aiuto anche se – Andrew

0

Una possibilità è quella di utilizzare la programmazione orientata agli aspetti di intercettare le invocazioni di proprietà sul ritorno e intorno al valore di ritorno prima di passare il controllo al chiamante.

4

modo più semplice per il refactoring del codice? Ecco quello che vorrei fare:

  1. Aprire Notepad ++ (ottenere se non si dispone di esso)
  2. Copia/incolla tutte le proprietà della classe in un'area di testo vuota.
  3. Posizionare il cursore all'inizio della prima riga: decimale pubblico MathValue1 {get; impostato; }
  4. Avviare la registrazione di una macro (fare clic sul pulsante di registrazione sulla barra degli strumenti)
  5. tenere premuto CTRL + freccia destra (chiamata "parola destra") 3 volte per posizionare il cursore all'inizio del nome della proprietà.
  6. fare shift + Ctrl + Freccia destra 1 tempo e fare una copia di mettere il nome della proprietà negli appunti
  7. parola giusta 3 volte per posizionare il cursore dopo il "get"
  8. eliminare il semi due punti dopo la tipizzazione ottenere e iniziare a "{return Math.round (_"
  9. fare una pasta 10 tipo ");}"
  10. parola giusta 2 volte per posizionare il cursore dopo il "set"
  11. cancella il punto e virgola dopo il set e inizia a digitare "{_"
  12. fare un Incolla
  13. digita "= valore; }
  14. premere il tasto Fine per portare il cursore alla fine della riga
  15. premere il tasto freccia destra per portare il cursore all'inizio della riga successiva.
  16. premere il pulsante stop per terminare la macro (pulsante quadrato sulla barra degli strumenti)
  17. Fare clic sul pulsante "Esegui una macro più volte" (un'icona a doppia freccia sulla barra degli strumenti) e pronunciare "Esegui fino alla fine del file "
  18. Copia/incolla il testo risultante nella classe per sostituire le definizioni di proprietà originali.

Ora è necessario definire un set di variabili private corrispondenti che iniziano con un trattino di sottolineatura, ma in caso contrario hanno gli stessi nomi delle proprietà. Inizia con una nuova copia delle proprietà della tua classe ed esegui una serie simile di passaggi come descritto sopra.

mia ipotesi è che ogni riga inizia con 2 linguette e non ci sono linee vuote tra le proprietà.

Piuttosto che chiamare ogni proprietà Math.Round, è possibile prendere in considerazione la possibilità di definire la propria funzione di utilità che chiamano tutti in modo tale che, se è necessario cambiarla nuovamente, è possibile modificarla in un unico punto.

+0

+1 - Non ne avrei mai pensato. Potrebbe voler colpire ctrl-k-d prima che lo faccia così VS pulirà tutto lo spazio bianco. – ChaosPandion

0

Si potrebbe fare questo con PostSharp o qualche altro quadro AOP basato su .NET. Ecco l'MethodExecutionEventArgs.ReturnValue property che dice che può essere usato per "modificare il valore di ritorno ..."

Questo lo farà:

[Serializable] 
public class RoundingAttribute : OnMethodBoundaryAspect 
{ 
    public override void OnExit(MethodExecutionEventArgs eventArgs) 
    { 
     base.OnExit(eventArgs); 
     eventArgs.ReturnValue = Math.Round((double)eventArgs.ReturnValue, 2); 
    } 
} 

class MyClass 
{ 
    public double NotRounded { get; set; } 

    public double Rounded { [Rounding] get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var c = new MyClass 
       { 
        Rounded = 1.99999, 
        NotRounded = 1.99999 
       }; 

     Console.WriteLine("Rounded = {0}", c.Rounded); // Writes 2 
     Console.WriteLine("Not Rounded = {0}", c.NotRounded); // Writes 1.99999 
    } 
} 
Problemi correlati