sobrecarga objetos metodos herencia ejemplos constructores clases c# struct optional-parameters default-constructor

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; } }



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.