Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.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
Generics F#在VS 2012和VS 2015之间处理不明确的通用接口之间的差异导致后者出现编译错误_Generics_Visual Studio 2012_Interface_F#_Visual Studio 2015 - Fatal编程技术网

Generics F#在VS 2012和VS 2015之间处理不明确的通用接口之间的差异导致后者出现编译错误

Generics F#在VS 2012和VS 2015之间处理不明确的通用接口之间的差异导致后者出现编译错误,generics,visual-studio-2012,interface,f#,visual-studio-2015,Generics,Visual Studio 2012,Interface,F#,Visual Studio 2015,(注:问题更新为完整的可复制示例) 将F#项目从VS 2012迁移到VS 2015后,我收到一个关于接口某些用法的错误。特别是当一个类型实现两个泛型接口时。我知道这是不允许直接在F#中使用的,但这种类型来自C# 要重现问题,请执行以下操作: 1.C#中的类型定义: 将其粘贴到某个类库中 公共接口基{} 公共接口IPrime:Base { T值{get;} } 公共接口IFloat:IPrime { } 公共接口IInt:IFloat、IPrime { int Salary{get;} } 公共抽

(注:问题更新为完整的可复制示例)

将F#项目从VS 2012迁移到VS 2015后,我收到一个关于接口某些用法的错误。特别是当一个类型实现两个泛型接口时。我知道这是不允许直接在F#中使用的,但这种类型来自C#

要重现问题,请执行以下操作:

1.C#中的类型定义: 将其粘贴到某个类库中

公共接口基{}
公共接口IPrime:Base
{
T值{get;}
}
公共接口IFloat:IPrime
{
}
公共接口IInt:IFloat、IPrime
{
int Salary{get;}
}
公共抽象类素数:IPrime
{
公共T值{get;受保护的内部集;}
公共静态隐式运算符T(素数值)
{
返回值;
}
}
公共类FFloat:Prime,IFloat
{
公共资源(双倍值)
{
这个。值=值;
}
公共双薪{get;set;}
}
公共类FInt:Prime,IInt
{
公共FInt(int值)
{
这个。值=值;
}
公共整数{get;set;}
int-ipinite.Value{get{返回此.Value;}}
double IPrime.Value{get{返回此.Value;}}
}
2.F#中类型的用法: 在Visual Studio 2012中的使用,工作:

open SomeClassLib

[<EntryPoint>]
let main argv = 
    let i = new FInt(10)
    let f = new FFloat(12.0)
    let g = fun (itm: SomeClassLib.Base) -> 
        match itm with
        | :? IInt as i -> i.Value
        | :? IFloat as i -> i.Value |> int
        | _ -> failwith "error"
Visual Studio 2015

| :? IInt as i -> i.Value          // Value is float
| :? IFloat as i -> i.Value |> int // Value is float
我想知道这种差异是从哪里来的

问题/备注 我觉得奇怪的是,编译器似乎“选择”了一个赋值有效,而另一个不起作用,这会导致不经意的错误,有时甚至很难出错。坦率地说,我有点担心,在类型推断可以在int和float之间选择的地方,它现在会倾向于float,在过去是int

2012年和2015年之间的区别似乎在于,前者在晋升时在遭遇中占据第一位,而后者似乎占据最后一位,但我无法明确证实这一点

这是一个bug还是对现有特性的改进?恐怕我需要做一些重新设计来消除歧义,除非有人知道一个简单的方法来处理这个问题(它只发生在大约50个地方,可以手工修复,但不是很好)

初步结论 我很清楚,原始类型可能被认为是不明确的,可能是糟糕的设计,但是.NET语言和MSIL都支持它

我知道F#不支持在同一方法或属性上混合泛型类型,这是一种我可以接受的语言选择,但它的类型推断会做出无法预测的决定,我认为这是一个bug


无论如何,我认为这应该是一个错误,类似于在F#中处理重载成员时得到的错误,在这种情况下,错误非常清楚,并列出了选项。

我将C#代码中的接口顺序替换为这段代码和下面在VS 2013中编译的代码

公共接口IInt:IPrime,IFloat
{
int Salary{get;}
}
let g=fun(itm:Base)->
将itm与
| :? 按i->i.值输入
| :? IFloat as i->i.值|>int
|->failwith“error”
根据接口的顺序,我怀疑一个“Value”成员被另一个隐藏(被FSharp的透视图遮蔽)

我将您的模式匹配编码为这样,并验证了在本例中,接口顺序并不重要

let g = fun (itm: Base) -> 
    match itm with
    | :? IPrime<int> as i -> i.Value
    | :? IPrime<float> as i -> i.Value |> int
    | _ -> failwith "error"
let g=fun(itm:Base)->
将itm与
| :? i优先于i->i.值
| :? i参数为i->i.值|>int
|->failwith“error”

在我看来,这似乎是实施细节上的一个变化。我不确定我是否会称之为bug。如果这是一个bug,那么F#规范将是最终的决定

我认为你应该消除歧义,不管是否有“好”的解决方案。还有,这在C#中是如何工作的?既然C#在
int
double
之间进行了隐式类型转换,那么您不担心C#中会发生这种情况吗?F#中的赋值是“因为两个接口都是由C#type实现的,所以它们不能有两个名为
add
的属性。一个(或两个)必须是显式接口实现(例如
float ITest.Add{get;set;}
)。你能把
iWithtware
的C#实现发布出来吗?@Daveshaw,让我检查一下(旧库,我们通常使用编译版本)。是的,我认为你是对的\@费奥多,我完全同意,但有时我们受到预算的限制,无法重新设计也用于其他项目或客户的冻结库……有趣的是,当直接粘贴到interactive:error FS0443中时,代码在
i上给出了一个相当明确的错误,这两个定义都是
定义:此类型在不同的位置实现相同的接口泛型实例化
ITest
ITest
。此版本的F#中不允许这样做。你应该看一看,不确定它是否符合复制品的条件。谢谢。我很惊讶地看到接口的顺序很重要,这是一个很大的优势,非常可疑。这是一个快速解决方案。我只是试了一下,没有100秒的演员失误,结果是零,太棒了!(虽然我仍然认为这是F#的一个缺陷)(ps,为我的上一条评论道歉,我说得太匆忙了)。嗯,需要补充的重要细节:在交换逗号分隔的接口列表顺序后,它在VS2015中编译得很好,但在VS2012中不再如此。幸运的是,我们不打算同时维护这两个版本。这也可能指出原因在于C#4和C#5编译器,不确定。
let g = fun (itm: Base) -> 
    match itm with
    | :? IPrime<int> as i -> i.Value
    | :? IPrime<float> as i -> i.Value |> int
    | _ -> failwith "error"