Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#比较vs C#i可比较_F#_Comparison_Icomparable - Fatal编程技术网

F#比较vs C#i可比较

F#比较vs C#i可比较,f#,comparison,icomparable,F#,Comparison,Icomparable,简而言之,我的问题是: 在需要IComparable的C#容器中存储元组(或具有“比较”约束的任何类型)时,我能做些什么 这项工作: > let x (y : 'a when 'a : comparison) = y ;; val x : y:'a -> 'a when 'a : comparison > x (1,2) ;; val it : int * int = (1, 2) 我本以为这会奏效: > let x (y : IComparable<int&g

简而言之,我的问题是:

在需要IComparable的C#容器中存储元组(或具有“比较”约束的任何类型)时,我能做些什么

这项工作:

> let x (y : 'a when 'a : comparison) = y ;;
val x : y:'a -> 'a when 'a : comparison

> x (1,2) ;;
val it : int * int = (1, 2)
我本以为这会奏效:

> let x (y : IComparable<int>) = y ;;

val x : y:IComparable<int> -> IComparable<int>

> x (1,2) ;;

  x (1,2) ;;
  ---^^^

stdin(28,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable<int>'
编辑

我遵循F#不做隐式向上投射的观点。然而,即使是明确的:

> (1, 2) :> IComparable ;;

  (1, 2) :> IComparable ;;
  ^^^^^^^^^^^^^^^^^^^^^

stdin(43,1): error FS0193: Type constraint mismatch. The type 
    int * int    
is not compatible with type
    IComparable    
The type 'int * int' is not compatible with the type 'IComparable'
我认为这是有意义的,因为F#元组的可比性是在F#类型系统中从结构上推断出来的,可能额外的信息对.NET不可用

下面的每个注释似乎都有一个解决方法

Tuple<_,_> (1,2) ;;
F#不像C#那样做隐式向上转换。如果您请求一个
IComparable
,那么您请求的是一个
IComparable
可以向上转换为
IComparable

您真正想要的是请求一个类型,该类型恰好实现了
IComparable
,但您仍在使用特定的类型

这就是为什么
让x(y:'a when'a:comparison)
,看到
y
'a
类型,而
'a
可以静态地向上转换为
比较
(如果你想访问
比较
的成员,你必须先使用
:>
向上转换为
比较

另一方面,
让x(y:IComparable)=y
非常明确地请求a
IComparable
。但是您正在传递
(1,2)
,一个可以向上转换为
i可比较的值。因此,如果您传递
(1,2):>IComparable
或甚至
(1,2):>,编译器将能够传递该值。您可以包装可比较的,但是如果丢失类型信息,返回值将是
i可比较的
,而不再是
int*int

let wrapComparable value = 
    {
        new IComparable with
            member this.CompareTo other = 
                match other with
                | :? 'a as other -> compare value other
                | _ -> raise <| InvalidOperationException()
    }
因此,根据经验,您通常希望生成具有类型约束的泛型函数,而不是像在C#中那样请求接口。这是因为F#不自动向上投射

关于相等性和比较的详细说明,请参见和。MSDN还声明

如果您只使用F#中的元组,而不将它们公开给其他语言,并且不针对版本4之前的.NET Framework版本,则可以忽略此部分

元组被编译成几个泛型类型之一的对象,这些泛型类型都是命名元组,它们在arity或类型参数的数量上重载。当您从另一种语言(如C#或Visual Basic)查看元组类型时,或者当您使用不知道F#构造的工具时,元组类型会以这种形式出现。元组类型是在.NETFramework 4中引入的。如果您的目标是.NET Framework的早期版本,编译器将使用F#Core库2.0版本中的System.Tuple版本。此库中的类型仅用于针对.NET Framework的2.0、3.0和3.5版本的应用程序。类型转发用于确保.NET Framework 2.0和.NET Framework 4 F#组件之间的二进制兼容性


所以看起来,事实上,元组恰好是一个系统。元组实际上只是一个实现细节,在这一点上,缺少
i比较有点道理。

肯定有些奇怪。FWIW,如果您显式地构造一个
System.Tuple
,它就会起作用,因此这可能是一个解决方法:

let x (y : IComparable) = y
let t = (2, 3)

x (Tuple<_,_> t)
设x(y:i可比较)=y
设t=(2,3)
x(元组t)

这看起来很奇怪,
int*int
实现了,
i可比较
(您可以使用
(1,2).GetType().GetInterfaces()
)检查这一点),但编译器不会让您失望。这可能是某种奇怪的F#限制。我想您可以编写一个C#方法来执行类型转换。我更新了我的回答,使其更加正确。对不起,我弄错了。谢谢你的推荐信。我想我的问题不是100%清楚。我特别感兴趣的是F#和C#之间的互操作,我的C#API需要一个IComparable,我无法将原始的、结构上可比较的元组传递到该API中。这看起来像是实现上的缺陷吗?好吧,如果没有看到C#签名,你的问题有点难以回答。但如果它是一个集合,即使在C#中,我也会使用受约束的泛型,因为返回接口会丢失一些类型信息。您正在使用的代码的签名是什么?
let wrapComparable value = 
    {
        new IComparable with
            member this.CompareTo other = 
                match other with
                | :? 'a as other -> compare value other
                | _ -> raise <| InvalidOperationException()
    }
let wrapComparable value = 
    {
        new IComparable<_> with
            member this.CompareTo other = compare value other
    }
let x (y : IComparable) = y
let t = (2, 3)

x (Tuple<_,_> t)