Instantiating types: when using new?
I have a type mapping a class in f# as follows:
type MyClass =
val myval: 开发者_StackOverflow社区integer
new () = {
myval = 0;
}
member self.MyVal with
get () = self.myval
Well, I want to create an instance of this class. I can do so:
let myinstance = MyClass ()
or
let myinstance = new MyClass ()
What's the difference? Can I do both?
Technically, one difference is that you should use new
when creating IDisposable
objects as nyinyithann already explained. Another difference is that you can omit type arguments when creating generic type:
// Works and creates Dictionary<int, string>
let r1 = System.Collections.Generic.Dictionary 10
r1.Add(10, "A")
// You get a compiler error when you write this:
let r2 = new System.Collections.Generic.Dictionary 10
r2.Add(10, "A")
Aside from these two things, there is no technical difference (and there is certainly no difference in the generated IL when you write or omit new
).
Which one should you use when? This is a matter of style. This is not covered by any F# coding standards, so it depends on your preference. Now that I'm thinking about it, I probably don't have very consistent style myself. I think I generally use new
when creating instances to be assigned to value using let
:
let rnd = new Random()
However, I usually don't use new
when creating objects to be used as arguments (e.g. Size
or Point
in the following example):
let frm = new Form(Size = Size(600, 400))
let gr = frm.CreateGraphics()
gr.FillRectangle(Brushes.Red, Rectangle(Point(0, 0), Point(100, 100)))
Possibly, I also prefer using new
for more complicated types and avoid it for simple types or for .NET value types (but I don't think I do this too consistently).
For types which implements IDisposable should be instantiated using new. Otherwise you will get the following compilation warning.
It is recommended that objects that support the IDisposable interface are created using 'new Type(args)' rather than 'Type(args)' to indicate that resources may be owned by the generated value
There is no difference. Both calls will create a a new object with exactly the same IL code.
.method public static void main@() cil managed
{
.entrypoint
// Code size 26 (0x1a)
.maxstack 4
.locals init ([0] class Program/MyClass myinstance,
[1] class Program/MyClass myinstance2)
IL_0000: nop
IL_0001: newobj instance void Program/MyClass::.ctor()
IL_0006: dup
IL_0007: stsfld class Program/MyClass '<StartupCode$fsharpapp>'.$Program::myinstance@11
IL_000c: stloc.0
IL_000d: newobj instance void Program/MyClass::.ctor()
IL_0012: dup
IL_0013: stsfld class Program/MyClass '<StartupCode$fsharpapp>'.$Program::myinstance2@12
IL_0018: stloc.1
IL_0019: ret
} // end of method $Program::main@
To decompile your binary you can use ildasm of the .NET Framework SDK which is in your path when you open a Visual Studio Command Prompt.
ildasm /CAVERBAL /out=fsharp.il fsharpapp.exe
The option CAVERBAL does print the content of attributes in a human readable form and not binary blobs as usual.
精彩评论