2011-01-25 10 views
4

F#不変型はC#とどのようにインターフェイスしますか?私はちょうどF#を学び始めています。私はそれをいくつかのC#コードと混在させたいのですが、私はF#クラスを不変にしたいと思っています。F#不変クラスInterop

F#でVectorクラスを作成しているとします。 Vector.XとVector.Yは再割り当て可能ですが、新しいVectorクラスのみを返す必要があります。 C#では、これは既存のオブジェクトを複製して新しいオブジェクトを返すために、.WithX(浮動小数点数x)を作るための足取りを必要とします。 F#でこれを行う簡単な方法はありますか?

私はしばらく時間を探していましたが、私はこれに関する文書を見つけることができません。だから、どんな助けも素晴らしいだろう。

最後に、このクラスをC#にインポートした場合、そのインターフェイスはどのように見えますか? F#のコードは、Vector.X = 10のような何か愚かなことを私に制限するのだろうか?

答えて

8

これは、C#でもF#でも同様です。

あなたは "それは取材がかかりますC#で" と言うが、CMON、私は

Vector WithX(float x) { return new Vector(x, this.Y); } 

は右、それはあると思いますか?

C#とF#の両方で、Xプロパティへの割り当てを禁止するには、 'getter'を持つプロパティを作成しますが、 'setter'は作成しません。

私はあなたがこれよりももっと難しくなっていると思っています。あるいは、あなたが求めていることを誤解しているかもしれません。そこに20フィールドであり、あなたはそれらのほんの任意のサブセットを変更することがありどこの(私は稀だと思う)場合のためにEDIT

は、私が一緒にF#とC#のオプションパラメータを使用するようにキュートなハックを見つけましたうまく。

F#コード:

namespace global 

open System.Runtime.InteropServices 

type Util = 
    static member Some<'T>(x:'T) = Some x 

type MyClass(x:int, y:int, z:string) = 
    new (toClone:MyClass, 
     [<Optional>] ?x, 
     [<Optional>] ?y, 
     [<Optional>] ?z) = 
      MyClass(defaultArg x toClone.X, 
        defaultArg y toClone.Y, 
        defaultArg z toClone.Z) 
    member this.X = x 
    member this.Y = y 
    member this.Z = z 

F#のクライアントコード:

let a = new MyClass(3,4,"five") 
let b = new MyClass(a, y=44) // clone a but change y 

C#クライアントコード:

ある
var m = new MyClass(3, 4, "five"); 
var m2 = new MyClass(m, y:Util.Some(44)); // clone m but change y 

は、オプションのパラメータは、これを行うには良い方法であり、 C#オプションのパラメータにはいくつかの制限がありますが、C#でうまく動作する方法でF#オプションのパラメータを公開することができます上のted。

+0

はい、これは簡単です。しかし、私が一人のクラスに20人のメンバーをいればどうなりますか?その場合、コンストラクタを呼び出すよりも "WithX(40)"を持つ方がずっと簡単です。多くの場合、そのクラスのメンバーから1人のメンバーを変更するだけでよいので、コンストラクターの引数としてそれらをすべて綴ると、少し冗長になります。 –

+0

そして、Z値を受け入れるようにVectorクラスを変更したいとしたら、WithX()、WithY()とVectorコンストラクタを変更して変更する必要があります。 –

+0

Stephenが指摘するように、レコードタイプはこの機能を提供します。代わりにクラスが必要な場合は、[this one](http://stackoverflow.com/questions/2873125/f-record-member-evaluation/2885063#2885063)などの回避策を使用できます。 – Daniel

6

のF#Record typesが正確にあなたが求めているものを行うための方法で構築している:それは、C#でinteropsどう

type Vector = {X:float; Y:float} 

let v1 = {X=1.; Y=2.} 
let v2 = {v1 with X=3.} 

を、私はわからないんだけど(編集:ブライアンさんのコメントを参照してください)。

XとYはセッターなしのゲッターとして実装されているため、Vectorはどの.NET言語からも変更できません。

+1

レコード 'with'構文は、他の引数を変更せずにコンストラクタを呼び出すためのF#構文sugarです。だから、 'interop'はありません。なぜなら、より冗長なコンストラクタ呼び出しをコード化する構文砂糖だからです。 – Brian