问题
I want to stick with record
, and don't want to go back to object
. So I am wondering if it is possible to make a field
of a record private
? or to make a private member
of record
. what about other concrete types
such as discriminated union
?
Or, does this requirement violate the language spec?
回答1:
Nope, it's not possible for single fields to be private: http://msdn.microsoft.com/en-us/library/dd233184
However, you can make all fields private and expose selected fields through properties. Note that you will need a Create-function in order to create an instance of the records, since its' fields are private:
type MyRec =
private
{ a : int
b : int }
member x.A = x.a
member private x.Both = x.a + x.b // Members can be private
static member CreateMyRec(a, b) = { a = a; b = b }
Members can be private though, as in the case of the MyRec.Both
property above.
Edit: The above makes the fields private to the module that MyRec is defined in, not private to MyRec. See Daniel's answer to Weird accessibility scopes when F# record's fields are declared private.
回答2:
The problem with this requirement is that the language features of record require the properties to be public. For example if you have a record r
of type R
with properties Name
and Age
and write{ r with Age = 20 }
, the compiler turns that into new R(r.Name, 20)
.
The idea is that with
copies all properties (excluding the one you want to change) and so it needs to be able to access them. For this, the compiler could actually generate methods for every possible with
use, but that could generate a lot of methods.
What are your reasons for prefering records? They have two nice features - the with
keyword (which you lose with private
members anyway) and structural equality (two instances are the same when they have the same values). Aside from that, classes seem to be easier to use, if you want to hide some fields.
Here is a simple example (which does not implement strucural equality):
type R(name:string, age:int) =
member x.Name = name
member x.WithAge(newAge) = R(name, newAge)
Using records with private
fields seems fine - although it may make more sense to use public fields within an implementation file and an F# signature file that hides the fields for all external users. This way, you can use features like with
in the implementation, but still hide the type.
回答3:
I don't think it's possible. MSDN says:
Record fields differ from classes in that they are automatically exposed as properties, and they are used in the creation and copying of records. Record construction also differs from class construction. In a record type, you cannot define a constructor.
"Automatically exposed" is a key to answer your question. Is three any reason why you don't want to create a new type?
来源:https://stackoverflow.com/questions/12389308/is-it-possible-to-make-a-field-of-a-record-private-or-to-make-a-member-of-recor