简体   繁体   English

F#不可变类Interop

[英]F# Immutable Class Interop

How do F# immutable types interface with C#. F#immutable类型如何与C#接口。 I'm just starting to learn F# and I'd like to mix it in with some C# code I have, but I want my F# classes to be immutable. 我刚刚开始学习F#,我想把它与我的一些C#代码混合在一起,但我希望我的F#类是不可变的。

Let's say we're making a Vector class in F#. 假设我们在F#中创建了一个Vector类。 Vector.X and Vector.Y should be re-assignable, but only be returning a new Vector class. Vector.X和Vector.Y应该是可重新赋值的,但只返回一个新的Vector类。 In C# this would take allot of legwork to make .WithX(float x) clone the existing object and return a new one. 在C#中,这需要花费大量的工作量.WithX(float x)克隆现有对象并返回一个新对象。 Is there an easy way to do this in F#? 在F#中有一种简单的方法吗?

I've been searching for some time and I can't seem to find any docs on this. 我一直在寻找一些时间,我似乎无法找到任何关于此的文档。 So any help would be great. 所以任何帮助都会很棒。

And finally, if I imported this class into C# what would its interface look like? 最后,如果我将这个类导入C#,它的界面会是什么样的? Will the F# code restrict me from doing something stupid like Vector.X = 10 ? F#代码是否会限制我做一些像Vector.X = 10这样愚蠢的事情?

This will look similar regardless of whether it's C# or F#. 无论是C#还是F#,这看起来都很相似。

You say "in C# it will take legwork", but cmon, I think 你说“在C#中它会需要腿部工作”,但我认为是cmon

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

is it, right? 这样对吗?

In both C# and F#, to prevent assignment to the X property, you author a property with a 'getter' but no 'setter'. 在C#和F#中,为了防止赋值给X属性,你要创建一个带有'getter'但没有'setter'的属性。

I think you're making all of this out to be harder than it is, or maybe I'm misunderstanding what you're asking. 我认为你所做的一切都比现在更难,或者我误解了你的要求。

EDIT 编辑

For the (I think rare) case of where there are 20 field and you may want to change just a small arbitrary subset of them, I found a cute hack to use F# and C# optional parameters together nicely. 对于(我认为罕见的)有20个字段的情况,你可能想要改变它们的一小部分,我发现一个可爱的黑客很好地使用F#和C#可选参数。

F# Code: 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# client code: F#客户端代码:

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

C# client code: C#客户端代码:

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

That is, optional parameters are a nice way to do this, and while C# optional parameters have some limitations, you can expose F# optional parameters in a way that works ok with C#, as suggested above. 也就是说,可选参数是一种很好的方法,虽然C#可选参数有一些限制,但您可以以一种适用于C#的方式公开F#可选参数,如上所述。

F# Record types have a built in way of doing exactly what you're asking: F# 记录类型有内置的方式来完成你所要求的:

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

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

How that interops with C#, I'm not sure ( edit: see Brian's comment ). 如何与C#进行交互,我不确定( 编辑:请参阅Brian的评论 )。

Vector will be immutable from any .NET language, since X and Y are implemented as getters without setters. Vector将是任何.NET语言都不可变的,因为X和Y实现为没有setter的getter。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM