2009-03-15 9 views
8

Esiste un modo per accedere al campo di supporto di una proprietà per eseguire la convalida, il rilevamento delle modifiche, ecc.?Accertamento del campo di supporto in una proprietà auto

È simile al seguente possibile? Se no, c'è qualche intenzione di averlo in .NET 4/C# 4?

public string Name 
{ 
    get; 
    set 
    { 
     if (value != <Keyword>) 
     { 
      RaiseEvent(); 
     } 
     <Keyword> = value; 
    } 
} 

Il problema principale che ho è che utilizzando le proprietà auto non consente la stessa flessibilità di convalida, ecc che una proprietà con un campo di supporto esplicito fa. Tuttavia un campo di backing esplicito ha lo svantaggio in alcune situazioni di permettere alla classe in cui è contenuto di accedere al backing field quando dovrebbe accedere e riutilizzare la validazione, il change tracking, ecc. Della proprietà come qualsiasi altra classe che potrebbe accedere la proprietà esternamente.

Nell'esempio precedente accesso al campo supporto sarebbe limitato l'ambito della proprietà impedendo così l'elusione della convalida di proprietà, il rilevamento delle modifiche ecc

Edit: ho cambiato < Backup Field> di < Chiave >. Proporrei una nuova parola chiave simile al valore. il campo farebbe bene anche se sono sicuro che viene utilizzato in un sacco di codice esistente.

risposta

3

Dopo aver letto i vostri commenti nella risposta di Mehrdad, penso di capire un po 'meglio il vostro problema.

Sembra che tu sia preoccupato per la capacità dello sviluppatore di accedere allo stato privato nella classe che stanno scrivendo, ignorando la tua logica di convalida, ecc. Ciò suggerisce che lo stato non dovrebbe essere contenuto nella classe.

Vorrei suggerire la seguente strategia. Scrivi una classe generica che rappresenti ValidatedValue. Questa classe contiene solo il valore di supporto e consente solo l'accesso/la mutazione tramite i metodi get e set. Un delegato è passato al ValidatedValue per rappresentare la logica di convalida:

public class ValidatedValue<T> 
{ 
    private T m_val; 
    public ValidationFn m_validationFn; 

    public delegate bool ValidationFn(T fn); 

    public ValidatedValue(ValidationFn validationFn) 
    { 
     m_validationFn = validationFn; 
    } 

    public T get() 
    { 
     return m_val; 
    } 

    public void set(T v) 
    { 
     if (m_validationFn(v)) 
     { 
      m_val = v; 
     } 
    } 
} 

Si potrebbe, ovviamente, aggiungere più delegati, come richiesto (ad esempio, per sostenere il cambiamento di notifica pre/post).

La classe ora utilizzerà ValidatedValue al posto di un backing store per la proprietà.

L'esempio seguente mostra una classe, MyClass, con un numero intero convalidato da essere inferiore a 100. Si noti che la logica per generare un'eccezione è in MyClass, non in ValidatedValue. Ciò consente di eseguire regole di convalida complesse che dipendono da altri stati contenuti in MyClass. La notazione Lambda è stata utilizzata per costruire il delegato di convalida: si sarebbe potuto associare a una funzione membro.

public partial class MyClass 
{ 
    private ValidatedValue<int> m_foo; 

    public MyClass() 
    { 
     m_foo = new ValidatedValue<int>(
      v => 
      { 
       if (v >= 100) RaiseError(); 
       return true; 
      } 
     ); 
    } 

    private void RaiseError() 
    { 
     // Put your logic here.... 
     throw new NotImplementedException(); 
    } 

    public int Foo 
    { 
     get { return m_foo.get(); } 
     set { m_foo.set(value); } 
    } 
} 

Speranza che aiuta - un po 'fuori tema originale, ma penso che sia più in linea con le vostre preoccupazioni attuali. Quello che abbiamo fatto è prendere la logica di validazione lontano dalla proprietà e metterla sui dati, che è esattamente dove volevi.

+0

È una buona soluzione ma un sacco di codice per accedere al campo nello stesso modo in cui accediamo al nuovo valore in un setter con la parola chiave value essere molto più succinti ed eleganti. –

+2

Probabilmente è possibile migliorare la sintassi aggiungendo operator = e coherion a T nella classe ValidatedValue. Fondamentalmente vuoi che si comporti come ValidatedValue è un T. –

1

Se lo farai, perché stai usando proprietà auto ?!

Una proprietà semplice ha fatto il passo indietro in 1.0. Non penso abbia senso aggiungere complessità al linguaggio per ogni caso particolare. O hai bisogno della proprietà per fare un semplice store/recuperare il modello o hai bisogno di qualcosa di più. In quest'ultimo caso, verrà eseguita una proprietà normale.

+0

Il vantaggio di proprietà di auto è che si è costretti a utilizzare la proprietà, piuttosto che il campo sostegno di metodi all'interno della classe. –

+0

Non vedo alcun vantaggio nel forzare una classe a non utilizzare ciò che dichiara. Questo è il motivo per cui non abbiamo meno di modificatori di accesso "privati". –

+0

Lo so, ma in alcuni casi il campo è semplicemente di archiviazione. Non c'è altro motivo per dichiararlo e si vuole essere in grado di controllare in che modo si accede a tale spazio di archiviazione, non importa dove sia. –

13

No, non c'è. Se si desidera accedere al campo di supporto, non utilizzare le proprietà automatiche e eseguire il rollover.

Sono d'accordo che sarebbe bello avere un campo che fosse accessibile solo dalla proprietà e non dal resto della classe. Lo userei sempre.

+0

Vorrei imporre l'uso della proprietà all'interno della classe in cui si trova la proprietà. Non voglio che il codice della classe acceda direttamente al campo. –

+3

Le classi devono essere in grado di fidarsi di se stesse per gestire correttamente i propri dati personali. –

+2

IMO questa è la risposta alla domanda * attuale *. La risposta contrassegnata come risposta è una risposta a una domanda tangenziale separata:/ – Catskul

1

Non puoi farlo, ho paura. Questo è uno dei motivi per cui ho iniziato a scrivere MoXAML Power Toys, per fornire la possibilità di convertire le proprietà automatiche in proprietà Notify.

+0

Sembra interessante.Ancora non risolve il problema di avere un campo in giro che non dovrebbe essere accessibile se non all'interno della portata della proprietà. –

6

quanto MSDN afferma:

"In C# 3.0 e versioni successive, auto-implementato caratteristiche rendono proprietà-dichiarazione più concisa quando non è richiesto logica addizionale nelle accesso alle proprietà Essi inoltre consentono. codice client per creare oggetti Quando si dichiara una proprietà come mostrata nell'esempio seguente, il compilatore crea un backing privato, anonimo è possibile accedere a tramite get della proprietà e impostare 01 Accessors. "

Poiché si dispone di una logica aggiuntiva in accessors, l'utilizzo di proprietà autoattive non è appropriato nello scenario.

Mentre il campo supporto esiste, viene assegnato un nome storpiato di fermarti riferimento facilmente - l'idea è che si mai direttamente riferimento campo.Per motivi di interesse, puoi utilizzare Reflector per smontare il tuo codice e scoprire il nome del campo, ma ti consiglio di non utilizzare direttamente il campo poiché questo nome potrebbe essere effettivamente volatile, quindi il tuo codice potrebbe interrompersi in qualsiasi momento.

+0

Avevo l'impressione che ragionassero solo per il nome straziato per assicurarsi che fosse unico. Non sono sicuro di come lo faccia comunque. Aggiunge caratteri strani che non sono validi per un nome di variabile. –

+0

Quello che non capisco è il motivo per cui il campo anonimo ha bisogno anche di un nome ... –

2

No, ma è possibile in una sottoclasse:

public class Base 
{ 
    public string Name 
    { 
     get; 
     virtual set; 
    } 
} 

public class Subclass : Base 
{ 
    // FIXME Unsure as to the exact syntax. 
    public string Name 
    { 
     override set 
     { 
      if (value != base.Name) 
      { 
       RaiseEvent(); 
      } 

      base.Name = value; 
     } 
    } 
}