2010-06-23 24 views
8

¿Hay alguna forma de acceder a los campos enlazados de un miembro estático? A continuación se presenta el error indicado:Acceder a dejar los campos vinculados de los miembros estáticos

type Foo(x) = 
    let x = x 
    static member test() = 
     let foo = Foo(System.DateTime.Now.Month) 
     printfn "%A" foo.x //the field, constructor or member 'x' is not defined 
     () 

mientras que los campos explícitos privados no permitir el acceso de los miembros estáticos:

type Bar = 
    val private x:int 
    new(x) = { x=x } 
    static member test() = 
     let Bar = Bar(System.DateTime.Now.Month) 
     printfn "%A" Bar.x 
     () 

La documentación http://msdn.microsoft.com/en-us/library/dd469494.aspx establece que "los campos explícitos no están destinados para su uso rutinario," sin embargo, el acceso a los campos privados de instancias de miembros estáticos son ciertamente un escenario de rutina. Además, no creo que pueda establecer campos explícitos dentro de un constructor primario, lo que significa que si se necesita acceder a un campo de instancia privada desde un miembro estático, todos sus campos se deben mover a campos explícitos y ya no se puede usa un constructor primario: es todo o nada.

Como ejemplo del mundo real donde realmente desearía acceder a un campo de instancia privada de un miembro estático, considere una implementación de entero grande: una clase BigInteger sería inmutable, por lo que la representación interna del entero grande se mantendría como privada campo de instancia (llamémoslo data). Ahora, supongamos que sintió que un método de instancia Add(other) era inapropiado para una estructura de datos inmutables y que solo quería implementar un método estático Add(lhs,rhs): en este caso, tendría que poder acceder a lhs.data y rhs.data.

Respuesta

6

no creo que pueda hacer eso ... de hecho, no se puede acceder a los valores de let-atado de otras instancias, ya sea:

type Foo() = 
    let x = 3 
    member this.Test(f:Foo) = 
    f.x // same error 

En general, si necesita acceder a tal valor desde fuera de la instancia a la que pertenece, probablemente debería crear una propiedad privada para obtener el valor o utilizar un campo privado en su lugar.

ACTUALIZACIÓN Esto esta cubierto por section 8.6.2 of the spec. En particular:

Instance “let” bindings are lexically scoped (and thus implicitly private) to the object being defined.

Tal vez alguien del equipo de F # pesará con una respuesta definitiva en cuanto a por qué el lenguaje se comporta de esta manera. Sin embargo, no puedo pensar en un par de razones posibles:

  1. permiten-unidos valores ni siquiera pueden estar presentes como campos (por ejemplo, de nuevo de la especificación, la unión será representado por un local al constructor "si se deja el valor no es una función sintáctica, no es mutable y no se usa en ninguna función o miembro ")
  2. Esto parece consistente con el comportamiento de dejar enlaces en otro lugar del lenguaje. Vea los ejemplos de una clase más o menos equivalente y las definiciones de registros que he incluido más abajo (porque parece que no puedo formatear correctamente los bloques de códigos dentro de una lista ordenada ...)
  3. Esto proporciona un nivel de encapsulación más detallado que es posible en muchos otros lenguajes: enlaces que son locales al objeto que se está definiendo. A menudo, otras instancias no necesitarán acceder a estas vinculaciones, en cuyo caso es bueno no exponerlas.
  4. Si desea algo a lo que puedan acceder otras instancias de su clase (o desde métodos estáticos), hay una manera fácil de hacerlo: crear un campo o propiedad privada, que tiene el beneficio de expresar explícitamente su intención de que valor sea accesible desde fuera de la instancia en la que se encuentre

Como se mencionó anteriormente, aquí hay una definición de clase más o menos equivalente y el método para crear un registro:

type MyClass(i:int) = 
    let j = i * i 
    member this.IsSameAs(other:MyClass) = 
    false // can't access other.j here 

type myRecord = { isSameAs : myRecord -> bool } 
let makeMyRecord(i:int) = 
    let j = i * i 
    { isSameAs = (fun r -> false) } //obviously, no way to access r.j here 

Desde constructores en F # son conceptualmente similares a cualquier otra función que devuelve una instancia de un tipo (por ejemplo, pueden llamarse sin usar new), llamar al MyClass 5 es conceptualmente similar a llamar al makeMyRecord 5. En el último caso, claramente no esperamos que haya ninguna forma de acceder al enlace de let local para j desde otra instancia del registro. Por lo tanto, es consistente que en el primer caso tampoco tengamos acceso al enlace.

+0

¿Hay alguna razón técnica o lógica por la que los campos enlazados se comporten de manera diferente en este aspecto a los campos privados explícitos? –

+1

@Stephen: consulta mi actualización para obtener información sobre por qué se ha llevado a cabo este enfoque. – kvb

+0

gracias. El hecho de que tengan un alcance léxico limita la capacidad del compilador para descubrirlos como campos en estos escenarios (¿"implícitamente privado" = oculto)? –

0

yet, accessing let bound fields from static members is certainly a routine scenario

¿Qué quiere decir aquí? ¿Cuál es el escenario de C# correspondiente (con un ejemplo)?

Tenga en cuenta que esto es legal:

type Foo() = 
    let x = 4 
    member this.Blah = x + 1 
    member private this.X = x 
    static member Test(foo:Foo) = 
     foo.X 

Es decir, puede exponer el valor let-atado como un miembro privado, que una estática puede leer/uso.

+0

Bueno, lo que realmente quiero decir es que accediendo a los campos/miembros de la instancia privada/etc. de una clase de miembros estáticos de la misma clase es un escenario común permitido por la mayoría de los lenguajes de programación ... incluso F #, hazlo cuando usas campos de instancia privados "val" explícitos. Mi observación es que esperaría que el constructor primario/deje que la sintaxis obligatoria sea exactamente eso: cuando dejo que los campos enlazados se compilen como campos, me gustaría que fueran accesibles con las mismas reglas que los campos privados ordinarios. –

+0

Veo - ver mi edición. – Brian

+0

Gracias, estaba pensando en adoptar ese enfoque, pero el principal problema que tengo es que creo que X es propiedad en lugar de campo (y prefiero usar un campo). –

Cuestiones relacionadas