Доступ к привязанным полям из статических элементов - PullRequest
9 голосов
/ 23 июня 2010

Есть ли способ получить доступ к привязанным полям из статического члена?Следующее дает указанную ошибку:

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
        ()

В то время как частные явные поля разрешают доступ из статических членов:

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

В документации http://msdn.microsoft.com/en-us/library/dd469494.aspx говорится, что «явные поляне предназначен для рутинного использования, но доступ к частным полям экземпляра из статических членов, безусловно, является обычным сценарием.Более того, я не верю, что вы можете установить явные поля в первичном конструкторе, что означает, что если к статическому члену требуется доступ даже к одному частному полю экземпляра, все ваши поля должны быть перемещены в явные поля, и вы больше не можетеиспользуйте первичный конструктор - все или ничего.

В качестве реального примера, где вы на самом деле хотите получить доступ к частному полю экземпляра из статического члена, рассмотрим реализацию большого целого числа: класс BigInteger будет неизменным,поэтому внутреннее представление большого целого числа будет храниться как частное поле экземпляра (назовем его data).Теперь предположим, что вы чувствовали, что метод экземпляра Add(other) не подходит для неизменяемой структуры данных, и вы хотели реализовать только статический метод Add(lhs,rhs): в этом случае вам потребуется доступ к lhs.data и rhs.data..

Ответы [ 2 ]

7 голосов
/ 23 июня 2010

Я не думаю, что вы можете сделать это ... на самом деле, вы не можете получить доступ к значениям let-привязки из других экземпляров:

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

В общем, если вам нужно получить доступ к такому значению за пределами экземпляра, к которому оно принадлежит, вам, вероятно, следует либо создать личное свойство для получения значения, либо использовать вместо него личное поле.

UPDATE Это покрыто разделом 8.6.2 спецификации . В частности:

Привязки экземпляра «let» лексически ограничены (и, следовательно, неявно частными) для определяемого объекта.

Возможно, кто-то из команды F # ответит на вопрос, почему язык ведет себя так. Однако я могу подумать о нескольких возможных причинах:

  1. значения let-привязки могут даже не присутствовать в виде полей (например, опять из спецификации, привязка let будет представлена ​​локальным для конструктора ", если значение не является синтаксической функцией, не является изменяемым и не используется в любой функции или члене ")
  2. Это, похоже, согласуется с поведением привязок let в других местах языка. Посмотрите примеры примерно эквивалентных определений классов и записей, которые я включил ниже (потому что я не могу правильно форматировать блоки кода в упорядоченном списке ...)
  3. Это обеспечивает более детальный уровень инкапсуляции, чем это возможно во многих других языках - привязки, которые являются локальными для определяемого объекта. Зачастую другие экземпляры не нуждаются в доступе к этим привязкам, и в этом случае желательно не показывать их.
  4. Если вы хотите что-то, что доступно другим экземплярам вашего класса (или из статических методов), есть простой способ сделать это - создать личное поле или свойство, которое имеет преимущество в явном выражении вашего намерения, что значение будет доступно снаружи экземпляра, в котором вы находитесь.

Как упоминалось ранее, вот примерно эквивалентное определение класса и метод для создания записи:

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

Поскольку конструкторы в F # концептуально похожи на любую другую функцию, которая возвращает экземпляр типа (например, они могут быть вызваны без использования new), вызов MyClass 5 концептуально аналогичен вызову makeMyRecord 5. В последнем случае мы явно не ожидаем, что существует какой-либо способ доступа к локальной привязке let для j из другого экземпляра записи. Следовательно, в первом случае у нас также нет доступа к привязке.

0 голосов
/ 23 июня 2010

пока, доступ к полям с привязкой let из статических элементов, безусловно, является обычным сценарием

Что вы имеете в виду здесь?Каков соответствующий сценарий C # (с примером)?

Обратите внимание, что это допустимо:

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

То есть вы можете выставить значение let-привязки как закрытый член, который статический может читать / использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...