2009-04-26 12 views
24

He leído un buen fragmento de Expert F # y estoy trabajando en la creación de una aplicación real. Durante la depuración, me he acostumbrado a pasar comandos FSI como este para hacer las cosas más legible en la ventana repl:¿Cómo personalizo la salida de un tipo personalizado usando printf?

fsi.AddPrinter(fun (x : myType) -> myType.ToString()) 

me gustaría extender esto a trabajar con el formateador printf, por lo que podría escribir, por ejemplo,

printf "%A" instanceOfMyType 

y controla la salida para un tipo personalizado. El libro implica que esto se puede hacer (p 93, "El formato estructural genérico se puede ampliar para trabajar con cualquier tipo de datos definido por el usuario, , un tema cubierto en el sitio web de F #"), pero no he encontrado referencias sobre cómo lograr esto realmente ¿Alguien sabe cómo? ¿Es posible?

Editar:

debería haber incluido un ejemplo de código, que es un tipo de registro que estoy tratando con, por ejemplo,

type myType = 
    {a: int}   
    override m.ToString() = "hello" 

let t = {a=5} 
printfn "%A" t 
printfn "%A" (box t) 

ambas declaraciones de impresión Producción:

{a = 5;} 

Respuesta

34

Parece que la forma correcta de hacer esto en C# 2.0 es mediante el atributo StructuredFormatDisplay, por ejemplo:

[<StructuredFormatDisplay("hello {a}")>] 
type myType = {a: int} 

En este ejemplo, en lugar del predeterminado {a = 42;}, se llega a hello 42.

Esto funciona de la misma manera para los tipos de objeto, registro y unión. Y aunque el patrón debe tener el formato "PreText {PropertyName} PostText" (pretexto y PostText siendo opcional), esto es en realidad más potente que ToString() porque:

  1. PropertyName puede ser una propiedad de cualquier tipo. Si no es una cadena, también estará sujeta al formato estructurado. Don Syme's blog da un ejemplo de formateo recursivo de un árbol de esta manera.

  2. Puede ser una propiedad calculada.Así que en realidad se podría conseguir ToString() a trabajar para el expediente y la unión tipos, aunque de una forma bastante rotonda manera:

    [<StructuredFormatDisplay("{AsString}")>] 
    type myType = 
        {a: int} 
        override m.ToString() = "hello" 
        member m.AsString = m.ToString() // a property that calls a method 
    

Por cierto, siempre se utilizará ToString() (incluso para grabar y sindicales tipos) si llama al printfn "%O" en lugar de printfn "%A".

+0

Por cierto, crédito a @Brian por publicar estos enlaces en un comentario de seguimiento a su respuesta. Solo pensé que valía la pena desarrollarse para cualquier otra persona que venga buscando. –

4

Hmm ... Recuerdo vagamente algunos cambios a este, pero me olvido si llegan antes o después de la CTP (1.9.6.2).

En cualquier caso, en la CTP, veo que

type MyType() = 
    override this.ToString() = "hi" 
let x = new MyType() 
let xs = Array.create 25 x 
printfn "%A" x 
printfn "%A" xs 

cuando se evalúa en la ventana VFSI hace lo que yo quiero, y que

x;; 
xs;; 

también imprime muy bien. Entonces, ¿no tengo claro cómo esto difiere de lo que se desea?

+0

Gracias; ver mi edición en la publicación original, es un tipo de registro con una función miembro añadida, y se comporta de forma diferente a un tipo de clase ... – flatline

+1

@Brian, sí, eso debería funcionar, pero como dice flatline, no funciona con unión y tipos de registro. Me encontré con esto hace un tiempo: http://cs.hubfs.net/forums/post/9163.aspx (no recuerdo si le envié algo a fsbugs cuando no recibí ningún seguimiento, lo siento) –

+0

Ver también http://blogs.msdn.com/b/dsyme/archive/2010/01/08/some-tips-and-tricks-for-formatting-data-in-f-interactive-and-a-in-sprintf- printf-fprintf.aspx y http://msdn.microsoft.com/en-us/library/ee370334.aspx – Brian

-1

Si reemplaza el método ToString, debería hacerlo.

Cuestiones relacionadas