Domanda

Ho una classe che definisce una proprietà di sola lettura che espone efficacemente un campo privato, qualcosa del genere:

public class Container
{
    private List<int> _myList;

    public List<int> MyList
    {
        get { return _myList;}
    }

    public Container() : base ()
    {
        _myList = new List<int>();
    }

    // some method that need to access _myList
    public SomeMethod(int x)
    {
         _myList.Add(x);
    }
}

ora è impossibile per il consumatore gestire direttamente la mia proprietà, quindi codice come aContainer.MyList = new List (); genera un errore in fase di compilazione. Tuttavia, il consumatore è assolutamente libero di chiamare tutti i tipi di metodi sul riferimento che ha ricevuto, quindi questo è un codice perfettamente valido

Container c = new Container();  
Console.WriteLine(c.MyList.Count);  
c.MyList.Add(4);  
Console.WriteLine(c.MyList.Count);  

che tipo di sconfigge l'intero concetto di sola lettura.

C'è qualche soluzione sana che mi consentirebbe di avere un vero riferimento di sola lettura in modo corretto?

P.S. Non posso semplicemente restituire una copia dell'elenco perché quindi l'utente penserà di aver apportato tutte le modifiche necessarie, ma purtroppo ... se ne andranno.

È stato utile?

Soluzione

Il riferimento è " readonly < !> quot; , l'oggetto reale. Cioè non è possibile sostituire il riferimento con un altro oggetto. Quindi se hai una classe che la interrompe in questo modo:

public class Container
{
    private readonly  List<int> _myList;

    public List<int> MyList
    {
        get { return _myList;}
    }

    public Container() : base ()
    {
        _myList = new List<int>();
    }

    public void BreakReadOnly()
    {
        _myList = new List<int>();
    }
}

& # 8230; quindi non verrà nemmeno compilato. È perché un campo di sola lettura non può essere riassegnato con nessun altro oggetto. In questo caso BreakReadOnly tenterà di assegnare un nuovo elenco.

Se vuoi davvero una sua raccolta in sola lettura, puoi farlo in questo modo:

    public ReadOnlyCollection<int> MyList
    {
        get { return _myList.AsReadOnly(); }
    }

Spero che questo aiuti.

Aggiornato : uso rimosso di IEnumerable.

Altri suggerimenti

Non restituire un riferimento diretto al tuo elenco. Restituisce invece un oggetto ReadOnlyCollection avvolto attorno ad esso, oppure se l'Elenco & Lt; & Gt; il tipo di ritorno è impostato su pietra, restituisce una copia del tuo elenco. Possono fare tutto ciò che vogliono sulla copia senza influire sull'originale.

Potresti restituire una raccolta di sola lettura in questo modo:

    public ReadOnlyCollection<int> MyList
    {
        get { return _myList.AsReadOnly(); }
    }

o restituisce un nuovo elenco in modo che il chiamante possa modificare l'elenco senza modificare l'elenco originale.

    public List<int> MyList
    {
        get { return new List<int>(_myList)}
    }

Dai un'occhiata al Array.AsReadOnly () metodo, che è possibile utilizzare per restituire un wrapper attorno a un array che ne impedisce la modifica.

Vuoi _myList, che è un tipo di riferimento di sola lettura. Bene, è di sola lettura e non c'è sconfitta del concetto di sola lettura.

Il CLR implementa una proprietà di sola lettura per i tipi di riferimento in modo tale che il riferimento (puntatore all'oggetto se lo si desidera) sia quello che viene fatto in sola lettura mentre l'oggetto a cui punta il riferimento può essere modificato.

Per ovviare a questo, è necessario creare i campi membri dell'oggetto stesso, di sola lettura, poiché non è possibile creare l'intero oggetto in sola lettura collegando un flag di sola lettura al riferimento dell'oggetto.

Puoi implementare la tua classe di raccolta generica immutabile che si comporterebbe allo stesso modo dell'elenco < > oggetto ma con membri di sola lettura.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top