Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.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
.net F#具有类型和接口继承的奇怪行为_.net_F#_Polymorphism - Fatal编程技术网

.net F#具有类型和接口继承的奇怪行为

.net F#具有类型和接口继承的奇怪行为,.net,f#,polymorphism,.net,F#,Polymorphism,这里有一段代码,经过几次尝试和错误后可以工作,但我不明白为什么它会以这种特殊的方式工作?在某些规范中,这些规则是设计出来的,并且是一成不变的,或者在这种情况下,这些规则是偶然发生的?代码中的注释解释了这一切,但具体问题是: 为什么类型B\u from_A没有看到IA.Item的槽已经由父A实现,但是它只允许部分实现IA,所以它实际上看到SharedMethod已经在父中实现 open System open System.Collections.Generic type IA = // onl

这里有一段代码,经过几次尝试和错误后可以工作,但我不明白为什么它会以这种特殊的方式工作?在某些规范中,这些规则是设计出来的,并且是一成不变的,或者在这种情况下,这些规则是偶然发生的?代码中的注释解释了这一切,但具体问题是:

为什么类型
B\u from_A
没有看到
IA.Item
的槽已经由父
A
实现,但是它只允许部分实现
IA
,所以它实际上看到
SharedMethod
已经在父
中实现

open System
open System.Collections.Generic

type IA = // only read methods
    abstract Item : int -> int with get
    abstract SharedMethod : int -> int

type IB = // allows in-place changes
    inherit IA
    abstract Item : int -> int with get, set

type IC = // immutable, returns new version with changes
    inherit IA
    abstract Set: int -> int -> IC

type A() =
    let dic = Dictionary<int,int>() // some complex internal data structure
    member internal this.Dic = dic
    member this.SharedMethod(i) = pown dic.[i] 2
    interface IA with
        member this.Item with get(i) = dic.[i]
        member this.SharedMethod(i) = this.SharedMethod(i) // custom operation on item

type B_from_A() =
    inherit A()
    // without this partial implementation I get an error:
    // Script1.fsx(111,18): error FS0361: The override 'get_Item : int -> int' 
    // implements more than one abstract slot, e.g. 'abstract member IB.Item : int -> int with get' 
    // and 'abstract member IA.Item : int -> int with get'
    interface IA with // partial interface implementation
        member this.Item with get(i) = this.Dic.[i] // required to remove error FS0361
        // !!! but there is no this.SharedMethod(i) here, so the type knows that this slot is 
        // implemented by parent A. Why it asks me to explicitly add Item get here?

    interface IB with
        member this.Item 
            with get(i) = this.Dic.[i] // implements more than one abstract slot without IA above
            and set i v = this.Dic.[i] <- v



type B() = // independent implementation
    let dic = Dictionary<int,int>()
    interface IA with
        member this.Item with get(i) = dic.[i]
        member this.SharedMethod(i) = pown dic.[i] 2
    interface IB with
        member this.Item  
            with get(i) = dic.[i]  
            and set i v = dic.[i] <- v
// If go from B to A, type A_from_B() won't be able to hide mutation methods in IB?
// It is more natural to add functionality than to hide or block it like some SCG ReadOnly collections do (e.g. throw on Add with InvalidOp)
// Therefore keep data structure inside A but add methods to change it inside B_from_A
开放系统
open System.Collections.Generic
类型IA=//仅读取方法
抽象项:int->int和get
抽象共享方法:int->int
类型IB=//允许就地更改
继承
抽象项:int->int带get,set
类型IC=//不可变,返回带有更改的新版本
继承
抽象集:int->int->IC
A型()=
让dic=Dictionary()//一些复杂的内部数据结构
成员内部信息。Dic=Dic
成员本。共享方法(i)=pown dic。[i]2
接口IA与
使用get(i)=dic成员此项。[i]
成员this.SharedMethod(i)=this.SharedMethod(i)//项上的自定义操作
输入B_from_A()=
继承
//如果没有此部分实现,我会遇到一个错误:
//Script1.fsx(111,18):错误FS0361:覆盖'get_Item:int->int'
//实现多个抽象槽,例如“抽象成员IB.项:int->int with get”
//和“抽象成员IA.Item:int->int with get”
接口IA与//部分接口实现
使用get(i)=this.Dic.[i]//成员this.Item以删除错误FS0361
// !!! 但是这里没有this.SharedMethod(i),所以类型知道这个插槽是
//由父级A实现。为什么它要求我显式添加项get here?
接口IB与
成员:本项目
with get(i)=this.Dic.[i]//实现了多个抽象插槽,但上面没有IA

设置iv=this.Dic.[i]此行为完全由规范定义

首先从8.14.3接口实现:

对接口实现的每个成员进行如下检查:

·该成员必须是实例成员定义

·应用调度时隙推断(§14.7)

·在假设“this”变量具有 封闭类型

然后是引用的部分:

14.7分派时隙推理F#编译器将分派时隙推理应用于它之前的对象表达式和类型定义 处理其成员。对于对象表达式和类型 定义,以下是调度时隙推断的输入:

·正在实现的类型ty0

·一套 成员重写x.M(arg1…argN)

·一套附加的 接口类型ty1。。。泰恩

·另一组成员 覆盖每个tyi的x.M(arg1…argN)

调度时隙推断 将每个成员与唯一的抽象成员或接口关联 收集的类型tyi定义或继承的成员


因此,每个函数只能工作一次-您无法获得所需的双重实现。

您描述的行为发生是因为
IB
继承
IA
,两者都定义了
属性访问器。因此,
B_From_A.IB.Item
属性访问器实现有两个可用插槽。但是,当您添加
B_From_A.IA.Item
实现时,一个槽已经被占用,因此类型推断没有歧义——只有
IB.Item
可由
B_From_A.IB.Item
实现

编辑 为了理解底层机制,必须知道在F#中实现接口层次结构有两种不同的方法:

现在,如果
IFoo
IBar
都有一个具有完全相同签名的成员(例如,在您的示例中,一个
Item
属性访问器),并且您仅通过
FooBar.IBar.Item
实现了该成员,则必然会出现类型推断歧义,因为
FooBar.IBar.Item
是否应该实现
IBar.Item
IFoo.Item
是未定义的行为

因此,您的问题的答案如下:

  • “…为什么它以这种特殊方式工作”:见上文
  • “这是设计的吗”:是的,另请参见@John的答案
  • “为什么类型
    B\u from_A
    没有看到
    IA.Item
    的插槽已由父
    A
    实现”:您的前提不正确。编译器确实看到了它,但它无法知道
    B_from_A.IB.Item
    是否应该
    • 重新实施(A)中已实施的
      IA.项目
      ,或
    • 实施
      IB.Item
  • “但是它只允许
    IA
    的部分实现,因此它实际上看到
    SharedMethod
    已经在父级中实现了。”如上所述,它看到
    IA.SharedMethod
    IA.Item
    都已经由父级
    A
    实现了,但这种模糊性与在
    A
    中“看到或不看到”任何预先存在的实现

VS 2013、.NET 4.0,在.fs、.fsx+FSI中同时使用F#3.0和3.1I进行了尝试。我不希望IB的Item_get在类型B_from_A中实现IA。随附类型B_from_A已经在其父级A中实现了IA的Item_get。很高兴您重复我的问题作为答案,但请重新阅读我的问题并详细说明后面句子中的陈述呃,"因此",为什么它有两个空位呢?
// ----- A hierarchy of interfaces
type IFoo = abstract FooMember: int

type IBar =
    inherit IFoo
    abstract BarMember: int

// Approach 1: Implement IFoo "explicitly".
// In the object browser, you will see both IFoo and IBar as parents of FooBar.
type FooBar =
    interface IFoo with member this.FooMember = 0
    interface IBar with member this.BarMember = 0

// Approach 2: Implement IFoo "implicitly" (as part of IBar).
// In the object browser, you will only see IBar as parent of FooBar.
type FooBar =
    interface IBar with
        member this.FooMember = 0
        member this.BarMember = 0