& # 8220; Solo lectura & # 8221; Accesorio de propiedad en C #
-
03-07-2019 - |
Pregunta
Tengo la siguiente clase:
class SampleClass
{
private ArrayList mMyList;
SampleClass()
{
// Initialize mMyList
}
public ArrayList MyList
{
get { return mMyList;}
}
}
Quiero que los usuarios puedan obtener mMyList, por eso expuse el " get " Sin embargo, a través de una propiedad no quiero que se realicen cambios en el objeto (es decir, MyList.Add (new Class ());) para regresar a mi clase.
Supongo que puedo devolver una copia del objeto, pero eso puede ser lento y estoy buscando una forma que proporcione un error de tiempo de compilación informando al usuario de que no deberían esperar poder modificar el objeto devuelto. valor de la propiedad.
¿Es esto posible?
Solución
Con un ArrayList estás bastante limitado porque no hay ninguna clase de colección no genérica de solo lectura en el BCL. La solución rápida y sucia es devolver un tipo de IEnumerable.
public IEnumerable MyList
{
get { return mMyList;}
}
En realidad, esto no evitará que alguien lance a ArrayList, pero tampoco permitirá ediciones por defecto
Puede devolver una lista de solo lectura efectiva llamando a ArrayList.ReadOnly. Sin embargo, su tipo de retorno es un ArrayList, por lo que el usuario aún podría compilar con .Add pero generaría un error de tiempo de ejecución.
Otros consejos
Use ArrayList.ReadOnly () método para construir y devolver un contenedor de solo lectura alrededor de la lista. no copiará la lista, sino que simplemente hará una envoltura de solo lectura alrededor de ella. Para obtener una verificación en tiempo de compilación, es probable que desee devolver el contenedor de solo lectura como IEnumerable como sugiere @Jared.
public IEnumerable MyList
{
get { return ArrayList.ReadOnly(mMyList); }
}
Una colección que es de solo lectura es simplemente una colección con una envoltura que impide modificar el colección. Si se realizan cambios en el colección subyacente, la de sólo lectura la colección refleja esos cambios.
Este método es una operación O (1).
Solo para ampliar la respuesta de JaredPar. Como dijo, devolver el campo de respaldo real no es completamente seguro, ya que el usuario aún puede convertir dinámicamente el IEnumerable
a una ArrayList
.
Escribiría algo como esto para asegurarme de que no se realicen modificaciones a la lista original:
public IEnumerable MyList
{
get
{
foreach (object o in mMyList)
yield return o;
}
}
Otra vez, probablemente también usaría una lista genérica ( IEnumerable < T >
) para estar completamente a salvo.
Utilice una ReadOnlyCollection
.
devuelve el nuevo ReadOnlyCollection < object > (mMyList)
.
También puede hacer que el ReadOnlyCollection
sea un campo, y reflejará automáticamente los cambios en la lista subyacente. Esta es la solución más eficiente.
Si sabe que mMyList solo contiene un tipo de objeto (por ejemplo, no tiene más que DateTimes),
puede devolver un ReadOnlyCollection < DateTime >
(o algún otro tipo) para seguridad de tipo adicional. Si está utilizando C # 3, simplemente puede escribir
devolver el nuevo ReadOnlyCollection < DateTime > (mMyList.OfType < DateTime > (). ToArray ())
Sin embargo, esto no se actualizará automáticamente con la lista subyacente, y también es menos eficiente (copiará la lista completa). La mejor opción es hacer de mMyList un List < T >
genérico (por ejemplo, un List < DateTime >
)
Debería envolver el valor de retorno en una colección de solo lectura.
Disponible desde .NET v2.0
public ArrayList MyList { get; private set; }
Simplemente haga la propiedad como Sellada (o NotInheritable en VB.NET) y de solo lectura, como esto:
public sealed readonly ArrayList MyList
{
get { return mMyList;}
}
Tampoco olvide hacer el campo de respaldo como de solo lectura:
private readonly ArrayList mMyList;
Pero para inicializar el valor de mMyList, debe inicializarlo SOLAMENTE en el constructor, como en este ejemplo:
public SampleClass()
{
// Initialize mMyList
mMyList = new ArrayList();
}