c# - Conceptos básicos de Console.Writeline
(3)
Tengo una pregunta sobre el siguiente código:
class CurrentDate
{
static void Main()
{
Console.WriteLine(DateTime.Now);
}
}
La documentación dice:
Escribe la representación de texto de la matriz de objetos especificada, seguida del terminador de línea actual, en la secuencia de salida estándar utilizando la información de formato especificada.
Entonces mi pregunta es: ¿por qué WriteLine
conoce la representación de texto del objeto DateTime
? Quiero decir, si creo mi propio objeto a partir de mi propia clase, ¿cómo sabría cómo convertir el valor en texto? Y aún más, ¿cómo sabe cuál es el valor? ¿Cómo puedes definir el "valor" de un objeto?
¿Cómo es que WriteLine conoce la representación de texto del objeto DateTime? Quiero decir, si creo mi propio objeto a partir de mi propia clase, ¿cómo sabría cómo convertir el valor en texto?
Console.WriteLine
tiene un conjunto de sobrecargas que coinciden con tipos específicos (principalmente primitivos). Si el compilador no hace coincidir una sobrecarga con el tipo provisto, coincide con la sobrecarga que toma System.Object
(concediéndole que proporcione un solo parámetro). Si eso sucede, verifica si el tipo implementa IFormattable
; si lo hace, invoca IFormattable.ToString(null, Formatter)
. Si no lo hace, invoca ToString
en su objeto. ToString
se define en System.Object
, del cual todos los objetos heredan. Cada objeto que desea una representación personalizada anula el comportamiento predeterminado, como lo hace DateTime
.
Por ejemplo, supongamos que tiene una clase Foo
con una propiedad de cadena de Bar
y desea que Console.WriteLine
imprima algo significativo cuando le pasa su Foo
:
public class Foo
{
public string Bar { get; set; }
public override string ToString()
{
return Bar;
}
}
Y ahora queremos pasarla a Console.WriteLine
:
public static void Main(string[] args)
{
var foo = new Foo { Bar = "bar" };
Console.WriteLine(foo);
}
Daría "bar".
Como no hay sobrecarga para Console.WriteLine(DateTime)
, como en su caso, se llama a la sobrecarga de Console.WriteLine(Object)
y esta sobrecarga llama a la sobrecarga de TextWriter.WriteLine(object)
que se implementa como :
IFormattable f = value as IFormattable;
if (f != null)
WriteLine(f.ToString(null, FormatProvider));
else
WriteLine(value.ToString());
Como puede ver, este método verifica si este tipo de objeto implementa la interfaz IFormattable
o no. Dado que Datetime
implementa esta interfaz , se f.ToString(null, FormatProvider)
su f.ToString(null, FormatProvider)
. De la documentation este método el primer parámetro es:
Una referencia nula (Nothing en Visual Basic) para usar el formato predeterminado definido para el tipo de implementación IFormattable .
Y a partir de la documentación del método DateTime.ToString(String, IFormatProvider)
:
Si el formato es nulo o una cadena vacía (""), se utiliza el especificador de formato estándar,
"G"
.
Eso significa que la representación será una combinación de las propiedades ShortDatePattern
y LongTimePattern
pertenecen a su CurrentCulture
Si desea un formato especial para su clase personalizada, puede anular el método .ToString()
de su tipo para cambiar su comportamiento.
Contrariamente a lo que piensan algunas personas, DateTime.ToString()
no se llamará. En .NET, un objeto puede tener dos formas de "encordarse": anular el método string Object.ToString()
e implementar la interfaz IFormattable
. DateTime
hace ambas cosas.
Ahora ... Cuando trates de hacer
Console.WriteLine(DateTime.Now);
se selecciona la sobrecarga public static void WriteLine(Object value)
(puede verla si presiona Ctrl + Clic en WriteLine
en Visual Studio). Este método simplemente llama al método TextWriter.WriteLine(value)
, que hace:
IFormattable f = value as IFormattable;
if (f != null)
WriteLine(f.ToString(null, FormatProvider));
else
WriteLine(value.ToString());
Todo esto se puede ver fácilmente usando ILSpy y buscando la Console.WriteLine
.