objetos - C#- Llamar a un constructor de estructura que tiene todos los parámetros predeterminados
sobrecarga de metodos c# ejemplos (5)
¿Por qué tienes public ExampleStruct(int value = 1) : this()
?
¿no debería ser public ExampleStruct(int value = 1)
? Creo que el :this()
está creando el constructor sin parámetros.
Me encontré con este problema hoy al crear una struct
para contener un montón de datos. Aquí hay un ejemplo:
public struct ExampleStruct
{
public int Value { get; private set; }
public ExampleStruct(int value = 1)
: this()
{
Value = value;
}
}
Se ve bien y elegante. El problema es cuando trato de usar este constructor sin especificar un valor y deseando usar el valor predeterminado de 1 para el parámetro:
private static void Main(string[] args)
{
ExampleStruct example1 = new ExampleStruct();
Console.WriteLine(example1.Value);
}
Este código genera 0
y no produce 1
. La razón es que todas las estructuras tienen constructores públicos sin parámetros. Entonces, al igual que cómo llamo a this()
mi constructor explícito, en Main
, ocurre lo mismo donde el new ExampleStruct()
llama a ExampleStruct()
pero no llama a ExampleStruct(int value = 1)
. Como lo hace, usa el valor por defecto de int
de 0 como Value
.
Para empeorar las cosas, mi código real está comprobando que el parámetro int value = 1
esté dentro de un rango válido dentro del constructor. Agregue esto al ExampleStruct(int value = 1)
arriba:
if(value < 1 || value > 3)
{
throw new ArgumentException("Value is out of range");
}
Entonces, tal como está ahora, el constructor predeterminado realmente creó un objeto que no es válido en el contexto en que lo necesito. Alguien sabe cómo puedo:
- A. Llame al
ExampleStruct(int value = 1)
. - B. Modifique cómo se rellenan los valores predeterminados para el constructor
ExampleStruct()
. - C. Alguna otra sugerencia / opción.
Además, soy consciente de que podría usar un campo como este en lugar de mi propiedad Value
:
public readonly int Value;
Pero mi filosofía es usar los campos de forma privada a menos que sean const
o static
.
Por último, la razón por la que estoy usando una struct
lugar de una class
es porque este es simplemente un objeto para contener datos no mutables, debe estar completamente poblado cuando se construye, y cuando se pasa como un parámetro, no debe ser capaz de ser null
(dado que se pasa por valor como una struct
), que es para lo que están diseñadas las estructuras.
No creo que sea un buen diseño tener una struct
ExampleStruct
tal que
default(ExampleStruct)
es decir, el valor donde todos los campos de instancia son cero / falso / nulo, no es un valor válido de la estructura. Y como sabes, cuando dices
new ExampleStruct()
eso es exactamente lo mismo que default(ExampleStruct)
y le da el valor de su estructura donde todos los campos (incluidos los campos "generados" de auto-propiedades) son cero.
Quizás puedas hacer esto:
public struct ExampleStruct
{
readonly int valueMinusOne;
public int Value { get { return valueMinusOne + 1; } }
public ExampleStruct(int value)
{
valueMinusOne = value - 1;
}
}
Supongo que el compilador actualmente selecciona el ctor predeterminado automático para las estructuras aquí http://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx , en lugar de usar su ctor con los valores predeterminados .
referencias añadidas: http://csharpindepth.com/Articles/General/Overloading.aspx (sección de parámetros opcionales)
En realidad, MSDN tiene una buena guía sobre struct
Considere la posibilidad de definir una estructura en lugar de una clase si las instancias del tipo son pequeñas y, por lo general, de corta duración o están comúnmente integradas en otros objetos.
No defina una estructura a menos que el tipo tenga todas las características siguientes:
Lógicamente representa un único valor, similar a los tipos primitivos (entero, doble, etc.).
Tiene un tamaño de instancia inferior a 16 bytes.
Es inmutable
No será necesario encasillarlo frecuentemente.
Tenga en cuenta que son consideraciones para considerar una struct
, y nunca es "esto siempre debe ser una estructura". Esto se debe a que la opción de usar una struct
puede tener implicaciones de rendimiento y uso (tanto positivas como negativas) y debe elegirse cuidadosamente.
Observe en particular que no recomiendan struct
para cosas> 16 bytes (entonces el costo de copiar es más caro que copiar una referencia).
Ahora, para su caso, realmente no hay una buena manera de hacer esto que no sea crear una fábrica para generar una struct
para usted en un estado predeterminado o hacer algún tipo de trick
en su propiedad para engañarla para que se inicialice en el primer uso.
Recuerde, se supone que una struct
funciona de tal manera que la new X()
== default(X)
, es decir, una struct
recién construida contendrá los valores por defecto para todos los campos de esa struct
. Esto es bastante evidente, ya que C # no le permitirá definir un constructor sin parámetros para una struct
, aunque es curioso que permitan que todos los argumentos sean predeterminados sin una advertencia.
Por lo tanto, en realidad te sugiero que te apegues a una class
y la vuelvas inmutable y solo verifiques los métodos a los que se aplica.
public class ExampleClass
{
// have property expose the "default" if not yet set
public int Value { get; private set; }
// remove default, doesn''t work
public ExampleStruct(int value)
{
Value = value;
}
}
Sin embargo , si absolutamente debe tener una struct
por otras razones, pero tenga en cuenta los costos de la struct
, como copiar, etc., podría hacer esto:
public struct ExampleStruct
{
private int? _value;
// have property expose the "default" if not yet set
public int Value
{
get { return _value ?? 1; }
}
// remove default, doesn''t work
public ExampleStruct(int value)
: this()
{
_value = value;
}
}
Tenga en cuenta que, de forma predeterminada, Nullable<int>
será null
(es decir, HasValue == false
), por lo tanto, si esto es cierto, no lo configuramos todavía, y podemos usar el operador nulo-coalescente para devolver nuestro valor predeterminado de 1
cambio Si lo configuramos en el constructor, será no nulo y tomará ese valor en su lugar ...
Aunque algunos lenguajes (CIL, nada más) permitirán definir un constructor de estructura tal que los new T()
tengan campos configurados en algo distinto de sus valores predeterminados de "todos los ceros", C # y vb.net (y probablemente la mayoría de los demás lenguajes) la opinión de que dado que cosas como los elementos de la matriz y los campos de clase siempre deben inicializarse a los valores default(T)
, y que tenerlos inicializados a algo que no coincide con la new T()
sería confuso, las estructuras no deberían definir new T()
para significar algo que no sea por default(T)
.
Sugeriría que, en lugar de intentar jinxar un parámetro predeterminado en un constructor parametrizado, simplemente defina una propiedad de estructura estática que devuelva el valor predeterminado que desee y reemplace cada aparición de new ExampleStruct()
con ExampleStruct.NiceDefault;
.
Addendum 2015
Parece que C # y VB.NET pueden facilitar la prohibición de definir constructores de estructuras sin parámetros. Esto puede hacer que una instrucción como Dim s = New StructType()
asigne s
un valor que sea diferente del valor otorgado a los nuevos elementos del tipo StructType
. No estoy muy interesado en el cambio, dado que el new StructType
se usa a menudo en lugares donde algo análogo al default(StructType)
C # default(StructType)
sería más apropiado si existiera. VB.NET permitiría Dim s As StructType = Nothing
, pero parece más bien hokey.