2009-06-02 10 views
33

Juro que he visto un ejemplo de esto, pero he estado buscando en Google por un tiempo y no puedo encontrarlo.C# devuelve una variable como solo lectura de get; conjunto;

Tengo una clase que tiene una referencia a un objeto y necesita tener un GET; método para ello. Mi problema es que no quiero que nadie pueda manipularlo, es decir, quiero que obtengan una versión de solo lectura, (tenga en cuenta que necesito poder modificarlo desde mi clase).

Gracias

+1

Me sorprende cuánta gente entendió mal la pregunta. Jon Skeet y Anton Gogolev lo hicieron bien. –

+1

No pensé que no entendí bien, pero aún así voté, oh bien – ChrisF

+0

fue una pregunta engañosa :) –

Respuesta

51

No, no hay manera de hacer esto. Por ejemplo, si devuelve un List<string> (y no es inmutable), las personas que llamen podrán agregar entradas.

La forma normal de hacerlo es devolver una envoltura inmutable, p. Ej. ReadOnlyCollection<T>.

Para otros tipos de variables, es posible que necesite clonar el valor antes de devolverlo.

Tenga en cuenta que el solo hecho de devolver una vista de interfaz inmutable (por ejemplo, devolver IEnumerable<T> en lugar de List<T>) no impedirá que un llamante vuelva al tipo mutable y mute.

EDIT: Tenga en cuenta que, aparte de todo lo demás, este tipo de preocupación es una de las razones por las cuales los tipos inmutables hacen que sea más fácil para razonar sobre el código :)

+2

+1 para clonación (excepto que ya hice +1 en) –

+2

Primero dice que no se puede hacer y luego señala a la solución de clonación. Además, tal vez la clonación es una idea nueva para C#, pero ha estado ahí por un largo tiempo en C++, por ejemplo. Tampoco está clonando estrictamente: está creando una copia de los datos internos y devolviendo esta copia, no los datos originales, la copia no tiene que ser del mismo tipo que el original. – mayu

6

devolver una referencia a una interfaz despojada:

interface IFoo 
    string Bar { get; } 

class ClassWithGet 
    public IFoo GetFoo(...); 
+1

Lo ideal es incluir una implementación 'privada' o 'interna' de IFoo para que no se pueda devolver;) – jerryjvl

+0

No, no, si la interfaz es interna o privada, no podrá devolver un miembro público que tenga un tipo no accesible. Esto no compilará: "Accesibilidad incoherente: tipo de campo ... es menos accesible que el campo ..." –

3

Esto no es posible. Obtenga y configure los descriptores de acceso a los tipos de referencia y establezca la referencia al objeto. Puede evitar cambios en la referencia mediante el uso de un ajustador privado (o interno), pero no puede evitar cambios en el objeto en sí mismo si es expuesto por un getter.

+0

Sí, es posible. Puede devolver una copia de los datos. – mayu

3

Si el objeto no es demasiado complicado/extenso, escriba una envoltura alrededor de él.

por ejemplo:

class A { 
    public string strField = 'string'; 
    public int intField = 10; 
} 

class AWrapper { 
    private A _aObj; 

    public AWrapper(A aobj) { 
     _aObj = A; 
    } 

    public string strField { 
     get { 
      return _aObj.strField; 
     } 
    } 

    public int intField { 
     get { 
      return _aObj.intField; 
     } 
    } 
} 

Así que ahora todo lo que hacemos es darle a su código de cliente de una instancia de la clase AWrapper para que sólo se pueden usar lo que les permite ver.

esto puede ser un poco complicado y no puede escalar bien si su clase base no está en piedra, pero para la situación más simple, puede que lo haga. Creo que esto se llama un patrón de fachada (pero no me cito en ese =))

0

estoy de acuerdo con ReadOnlyCollection

Ver mi código simple:

private List<Device> _devices; 
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices 
{ 
get 
{ 
return (_devices.AsReadOnly()); 
} 

}

ReadOnlyCollection no tiene el método Agregar para que el usuario no pueda agregarle propiedades. SIN EMBARGO, no hay garantía de que el usuario pueda modificar objetos llamando a sus métodos ...

1

Su pregunta se lee como que estás buscando:

public PropertyName { get; private set; } 

Pero entonces, dadas las respuestas hasta el momento no estoy seguro de que estoy interpretando bien su pregunta. Además, ¿quién soy para interrogar a Jon Skeet? :)

+0

Devuelve una referencia que es de solo lectura, ya que no se puede asignar, pero aún puede editar el objeto porque sus propiedades no son solo de lectura – DCShannon

0

Me he enfrentado a este problema de cierta manera. tengo una clase CategoryViewModel, que tiene una categoría de propiedad que quiero de sólo lectura privada:

public CategoryViewModel 
{ 
    private Category { get; } 

} 

De hecho, yo quiero que sea exportado como de sólo lectura a otra clase. Sin embargo, no puedo hacer tal cosa. En mi caso (tal vez ayudará a otros chicos), quiero agregarlo a un repositorio. La única forma que he encontrado es tener una función con el repositorio como parámetro 1, y una acción como parámetro 2:

public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action) 
{ 
    action(repo, Category); 
} 

Al igual que, de otra parte, no puedo hacer tal cosa:

categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c)); 

Esto puede ayudar a otros a exponer su propiedad solo en algunos casos y puede administrarlos.

Cuestiones relacionadas