我今天决定用F#练习,发现了一件有趣的事情。我将在C#和F#中提供类似的代码,但使用DAO(数据访问对象)的行为却截然不同:
C#版本:
interface IPoint2D
{
int X { get; set; }
int Y { get; set; }
}
class Point2D : IPoint2D
{
private int _x = 0;
private int _y = 0;
public int X { get { return _x; } set { _x = value; } }
public int Y { get { return _y; } set { _y = value; } }
}
F#版本:
type IPoint2D =
abstract member X: int
abstract member Y: int
type Point2D(x: int, y: int) =
let _x = 0
let _y = 0
interface IPoint2D with
member this.X = x
member this.Y = y
使用C#的第一个区别非常明显,我必须将成员声明为public
以获得实施合同。
但是,为什么F#允许将接口实现为私有成员?有什么意义?
答案 0 :(得分:2)
F#需要对象进行向上转换才能直接访问其接口。 let x = (firstPoint :> IPoint2D).X
F#支持函数参数的隐式接口转换。它过去需要泛型,但已在更新版本的语言中更新。
let Distance (a:IPoint2D) (b:IPoint2D) =
(a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y)
|> float |> Math.Sqrt
let firstPoint = new Point2D(2, 3)
let secondPoint = new Point2D(4, 5)
let distance = Distance firstPoint secondPoint
printf "%f" distance
并非所有人都同意,但作为设计规则,不应该对对象进行直接访问。这样做会增加代码耦合。如果编写了调用对象接口上的方法的代码,则在不更新所有调用瞄准器的情况下,无法轻松更改该对象类。
如果接口是带有x,y,z的IPoint3D并且您想将其更改为IPoint2D,那么所有引用z的转换都必须更新而不仅仅是像Distance这样的接口消费者。
我认为这种设计选择是为了与语言的其余部分保持一致,并在使用OOP时促进更松散的耦合。 2014年有一个user voice feature request没有得到答复,要求进行隐式上传。