2011-02-15 17 views
7

Estoy tratando de crear un tipo complejo y necesito, en el momento de la construcción, realizar algunas acciones. así que empecé a escribir mi código:Comprender los constructores tipo F #

type public MyType = 
    val private myvar: int 
    val private myvar2: string 
    (* ...Some val declarations... *) 
    new() = { 
     (* The default ctor makes something *) 
    } 
    new (ctorpar: AnotherType) = { 
     myvar = 1; 
     myvar2 = "Hello"; 
     (* Other assignments in the form var = val *) 
     (* Here I would like to start a cycle in order *) 
     for i in ctorpar.array do 
     (* Do something *) (* ERROR *) 
    } 

bien cuando se trata de colocar una a favor o en algo más de una asignación que el compilador se vuelve loco. Supongo lo siguiente: La sintaxis para nuevo sigue a la de Expresiones Computacionales, o mejor, la nueva es una expresión computacional (I implica esto debido a los corchetes y el punto y coma de una instrucción a otra). Y en este caso, para las expresiones computacionales del constructor, es posible ubicar solo las asignaciones.

Así que por favor, ¿podría contestar:

1) ¿Es mi deducción correcta? (con respecto a las expresiones computacionales y el constructor para los tipos).

2) ¿Qué debo hacer si necesito colocar un conjunto articulado de instrucciones para ser ejecutado en el constructor ???? Bueno, ya sabes, a veces es necesario realizar una acción en el momento de la construcción y puede involucrar todo, desde un ciclo hasta todas las posibilidades.

Pero el compilador se vuelve loco de todos modos ...

Gracias a KVD entendí que tengo la posibilidad de hacer lo siguiente:

type public MyType = 
    val private myvar: int 
    val private myvar2: string 
    (* ...Some val declarations... *) 
    new() = { 
     (* The default ctor makes something *) 
    } 
    new (ctorpar: AnotherType) = 
     for i in ctorpar.ACollection do 
     (* Something *) 
     { 
     myvar = 1; 
     myvar2 = "Hello"; 
     } 

Bueno lo siento, pero esto no me ayuda porque F # compilador me dice esto:

constructores de objetos pueden no directamente utilización tratar/y tratar con/por último antes de la la inicialización del objeto. Este incluye constructores como 'para x en ...' que pueden detallar los usos de estos constructos. Esta es una limitación impuesta por Common IL.

bien, si el problema es hacer algo antes de la initalization objeto, y suena correcto, entonces vamos a hacer esto después:

type public MyType = 
    val mutable private myvar: int 
    val mutable private myvar2: string 
    (* ...Some val declarations... *) 
    new() = { 
     (* The default ctor makes something *) 
    } 
    new (ctorpar: AnotherType) = 
     { 
     myvar = 1; 
     myvar2 = "Hello"; 
     } 
     then 
     for i in ctorpar.ACollection do 
     (* Something *) 
     myvar <- 10 

Una vez más frustrados por el fracaso:

El el valor o el constructor 'myvar' es no definido.

¿Qué debo hacer ???? Parece que después, no reconoce los elementos en mi clase, parece correcto porque requeriría un identificador en cuanto a cuando se declaran miembros usando uno mismo o esto ... aquí no tiene una autorreferencia y, correctamente, dice yo: "¡Estás tratando de obtener algo que no puedo darte!"

Respuesta

13
  1. No, su inferencia es incorrecta. Las llaves son más como una expresión de construcción de registro, que solo puede contener asignaciones de campo. No puede hacer nada más que asignar valores a cada campo dentro de las llaves.

  2. Puede poner las instrucciones antes de las asignaciones de campo (es decir, antes de la llave de apertura) de forma normal. Si a continuación desea ejecutar otras declaraciones después, es necesario utilizar la palabra clave then:

    type public MyType = 
        val private myvar: int 
        val private myvar2: string 
    
        new() = 
        for i in 1 .. 10 do 
         printfn "Before field assignments %i" i 
        { myvar = 1; myvar2 = "test" } 
        then 
         for i in 1 .. 10 do 
         printfn "After field assignments %i" i 
    

Editar

En cuanto a su nueva pregunta, puede utilizar new (ctorpar:AnotherType) as this = ... y luego this.myvar <- 10.

+0

kvb muchas gracias, realmente me aclaras todo, no solo lo que acabo de preguntar, sino aún más. AHORA TIENE SENTIDO. Muchas gracias. – Andry

+0

¿Dónde aparece la palabra clave "then" en la documentación? Definitivamente funciona, pero no creo haberlo visto antes. –

+1

@Ramon: consulte la sección "Ejecución de los efectos secundarios en los constructores" de http://msdn.microsoft.com/en-us/library/dd233192.aspx. – kvb

9

La respuesta de kvb es excelente y le brinda toda la información que solicitó :-).

Me gustaría recomendar el uso de la sintaxis implícita donde el constructor principal se escribe inmediatamente después del nombre del tipo. Esto hace que muchas cosas sean mucho más fáciles:

type MyType(n:int, s:string) = 
    do 
    // Run before fields initialized (they aren't accessible here) 
    for i in 1 .. 10 do 
     printfn "Before field assignments %i" i 
    // Initialize fields (accessible from now on) 
    let myvar = n 
    let myvar2 = s 
    do // Run after fields initialized - you can use them here 
    for i in 1 .. 10 do 
     printfn "After field assignments %i" i 

    // You can add multiple constructors too: 
    new() = MyType(0, "hi") 
    member x.Foo = 0 
+2

De hecho, consulte también http://lorgonblog.wordpress.com/2009/02/13/the-basic-syntax-of-f-classes-interfaces-and-members/ – Brian

+0

Tomas Petricek y @kvb como siempre, ustedes dos son una gran ayuda con todas las cosas F #. –

Cuestiones relacionadas