使用编译时检查键入别名?

时间:2014-01-16 16:03:12

标签: f# typechecking type-alias

类型别名不提供编译时类型检查

类型别名非常便于缩短长类型名称。类型别名'只是合成糖,在运行时被编译成别名类型,这意味着代表相同类型的两个不同别名可以互换使用而不会出错:

type foo = int
type bar = int

let x : foo = 5
let y : bar = x
  

type foo = int
  type bar = int
  val x : foo = 5
  val y : bar = 5

我理解为什么你不希望将它们视为具有编译时类型实施的常规类型。不过,在某些情况下,它会非常方便。

有时,我需要区分代表不同内容的整数

例如,我从具有多种不同类型值的COM库导入一些函数,但它们在我的代码中都表示为int

[<DllImport(@"C:\API\COMAPI.dll", EntryPoint="Foobar")>]
extern int Foobar ( int hPool, int hServer )

在C中,hPool的类型为APIPhServer,函数返回类型均为APIV

typedef unsigned long  API_INDEX;      // index 
typedef API_INDEX    * APIV;           // value handle
typedef void         * APIP;           // pool  handle

我想用不同的类型来表示这些不同的类型,代表不同的东西,它们提供了一些编译时类型的实现。这样,我就不会意外地将APIP传递给期待APIV的函数。

措施让我在那里中途,但需要大量额外的绒毛

到目前为止,我发现的唯一解决方案是使用测量:

type [<Measure>] APIP
type [<Measure>] APIV

不幸的是,似乎无法直接向外部人员添加措施:

[<DllImport(@"C:\API\COMAPI.dll", EntryPoint="Foobar")>]
extern int<APIV> _Foobar ( int<APIP> hPool, int<APIV> hServer )
  

error FS0010: Unexpected type application in extern declaration. Expected identifier or other token.

所以我不得不编写一个包装函数,导致大量的额外代码:

[<DllImport(@"C:\API\COMAPI.dll", EntryPoint="Foobar")>]
extern int private _Foobar ( int hPool, int hServer )
let Foobar ( hPool : int<APIP> ) ( hServer : int<APIV> ) : APIV =
    _Foobar( int hPool, int hServer ) |> LanguagePrimitives.Int32WithMeasure

乘以数十个和几十个导入的函数,这变得非常臃肿和厌倦。

有没有更直观的方法来解决这个问题,还是我决定在编译时类型检查和合理可读的代码之间做出决定?

0 个答案:

没有答案