c# - texto - validar que los textbox no esten vacios visual basic
¿Cómo evitar el acceso público a campos privados? (7)
¿Qué hay de usar un ReadOnlyCollection
. Eso debería arreglar ese problema en particular.
private ReadOnlyCollection<string> foo;
public IEnumerable<string> Foo { get { return foo; } }
Por ejemplo, declaremos:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get
{
return _strings;
}
}
Y ahora podemos hacer lo siguiente:
((List<string>) obj.Strings).Add("Hacked");
Así que realmente no estamos ocultando la List
del uso, solo la ocultamos detrás de la interfaz. ¿Cómo ocultar la lista en dicho ejemplo sin copiar _strings
en la nueva colección para restringir la modificación de la lista?
Acabo de publicar mis pensamientos recientes sobre la encapsulación, puede que los encuentre razonables.
Como todos saben, la encapsulación es algo muy útil, ayuda a combatir la complejidad. Hace que su código sea lógicamente minimalista y claro.
Como dijo, el acceso protegido al miembro se puede interrumpir y el usuario de la interfaz puede obtener acceso completo al objeto subyacente. ¿Pero cuál es el problema con eso? Su código no se volverá más complicado o acoplado.
En realidad, por lo que sé, con el uso de alguna reflexión casi no hay restricciones, incluso con miembros totalmente privados. Entonces, ¿por qué no intentas esconderlos también?
Creo que no hay necesidad de hacer una copia de una colección (o de cualquier otro modificable) y los enfoques anteriores son incorrectos. Usa tu variante inicial:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get
{
return _strings;
}
}
Aparte de ReadOnlyCollection
hay colecciones inmutables para .NET disponibles.
El uso de colecciones inmutables garantiza al consumidor que la colección no cambia en lugar de simplemente no puede cambiarla . Como son inmutables puedes exponerlos:
public ImmutableList<string> Strings { get; private set; }
Más detalles: http://blogs.msdn.com/b/bclteam/archive/2012/12/18/preview-of-immutable-collections-released-on-nuget.aspx
Como nadie ofreció esto como respuesta todavía, aquí hay otra alternativa:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get { return _strings.Select(x => x); }
}
De hecho, es equivalente al método de yield return
mencionado anteriormente, pero un poco más compacto.
De muchas maneras.
El enfoque más ingenuo sería copiar siempre el campo privado:
return _strings.ToList();
Pero eso no es generalmente necesario. Sin embargo, tendría sentido si:
- Por casualidad, sabe que el código de llamada generalmente querrá una
List<T>
, así que también puede devolver uno (sin exponer el original). - Es importante que el objeto expuesto mantenga los valores originales incluso si la colección original se modifica posteriormente.
Alternativamente, puedes exponer un envoltorio de solo lectura:
return _strings.AsReadOnly();
Esto es más eficiente que la primera opción, pero expondrá los cambios realizados en la colección subyacente.
Estas estrategias también podrían combinarse. Si necesita una copia de la colección original (por lo que los cambios en el original no tienen efecto) pero tampoco quiere que el objeto devuelto sea mutable *, podría ir con:
// copy AND wrap
return _strings.ToList().AsReadOnly();
También podrías usar el yield
:
foreach (string s in _strings)
{
yield return s;
}
Esto es similar en eficiencia y compensaciones a la primera opción, pero con ejecución diferida.
Claramente, la cosa clave a considerar aquí es cómo se usará realmente su método y qué funcionalidad, exactamente, pretende proporcionar con esta propiedad.
* Aunque para ser honesto, no estoy seguro de por qué te importaría.
Podrías envolver tu lista en el captador así:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings {
get {
return new ReadOnlyCollection<string>(_strings);
}
}
De esa manera, puede modificar libremente su lista privada dentro de su clase y no preocuparse por los cambios externos.
NOTA: ReadOnlyCollection
no copia la lista que contiene (por ejemplo, _strings)
ReadOnlyCollection<T>
: ReadOnlyCollection
Inicializa una nueva instancia de la clase ReadOnlyCollection que es un contenedor de solo lectura alrededor de la lista especificada.