Object 表达式和错误 FS0419:'base' 值只能用于直接调用覆盖成员的基本实现
Object expressions and error FS0419: 'base' values may only be used to make direct calls to the base implementations of overridden members
标题中的错误含糊不清,但 googling it 目前对 SO 有两次点击,总共有五次点击(表明它是一种稀有动物,所以不要指望这里有太多访问 ;)。我希望这个问题在该列表中排在第六位:p。
Kvb's answer in this thread 表明错误文本具有误导性,如果您从闭包中调用 base 则会引发错误文本,但情况似乎并非总是如此,因为这是有效的:
// in a closure, but no FS0419
let myObj = fun foo ->
{ new obj() with override this.ToString() = base.ToString() + foo}
但这失败了(我发现最简单的方法来举例说明这个问题):
// not in a closure, but raises FS0419
let myObj =
{ new obj() with override this.ToString() = () |> base.ToString }
我使用的是 object 表达式而不是具有继承的类型声明,并且我尝试通过构建自定义 NUnit 约束来创建新的 FsUnit 约束。这是显示我遇到的问题的简化版本:
let EndsWithIgnoreWhitespaceContraint expectedResult =
{ new EndsWithConstraint(expectedResult) with
override __.ApplyTo<'T> (actual: 'T) =
let actual = box actual
if actual :? string then
actual :?> string
|> fun s -> if isNull s then String.Empty else s
|> fun s -> s.Trim()
// error FS0419: 'base' values may only be used to make direct
// calls to the base implementations of overridden members
|> base.ApplyTo
else
exn "String expected .. bla bla..." |> raise }
// make it available to FsUnit's syntax style (overriding existing endWith)
let endWith = EndsWithIgnoreWhitespaceContraint
// using it:
" hello world " |> should endWith "world"
现在,显然不需要知道 FsUnit 就可以看到这种行为。但是我花了一天一夜的时间才意识到我被骗了,事实上直到我在 SO 上写这个问题我才看到它。
事实证明这有效:
而不是 x |> base.SomeMethod
写 base.SomeMethod x
.
我觉得这很奇怪。不确定这是错误还是功能。但是由于 |>
运算符是内联的(我用不同的运算符对其进行了测试)并且它没有创建新函数(就像 >>
那样),所以我不明白为什么会出现此错误。
事实上,我没有看到 f a
和 a |> f
之间有任何语义差异(除了优先规则等)。那么为什么会出错呢?我违反了什么规则?
最后一个想法,kvb 写道“base
不能从闭包中调用...柯里化成员自动创建闭包”,这表明这是错误的,但它编译得很好:
let myObj foo bar =
{ new obj() with override this.ToString() = base.ToString() + foo + bar}
是否有人确切知道导致或不导致此错误的原因?
首先,您误解了“base 不能在闭包中使用”的答案。它的意思是指一个闭包 捕获基本身 - 是捕获阻止了它的工作,而不是闭包本身。在您的 { new obj }
示例中, base
未被任何闭包捕获。捕获了整个对象,但 base
仅在 ToString
方法中直接使用。
为了说明,试试这个:
let myObj =
{ new obj() with override this.ToString() = (fun() -> base.ToString())()}
此代码无法编译,因为 base
正在被闭包 fun() -> base.ToString()
.
捕获
其次,将对象方法用作函数并不像人们预期的那样有效 "directly",因为 .NET 方法的表示方式与 F# 函数不同。相反,当遇到类似 let x = obj.M
的内容时,编译器会将其视为 let x = fun a -> obj.M(a)
- 即,将其包装在闭包中。
为了说明,试试这个:
let myObj =
{ new obj() with
override this.ToString() =
let f = base.ToString // Error here
f()
}
看到这是怎么回事了吗? :-)
当您通过管道输入对象方法时,编译器必须创建该闭包,然后将其传递给管道运算符。为了说明,试试这个:
let myObj =
{ new obj() with
override this.ToString() =
() |> base.ToString // Same error
}
标题中的错误含糊不清,但 googling it 目前对 SO 有两次点击,总共有五次点击(表明它是一种稀有动物,所以不要指望这里有太多访问 ;)。我希望这个问题在该列表中排在第六位:p。
Kvb's answer in this thread 表明错误文本具有误导性,如果您从闭包中调用 base 则会引发错误文本,但情况似乎并非总是如此,因为这是有效的:
// in a closure, but no FS0419
let myObj = fun foo ->
{ new obj() with override this.ToString() = base.ToString() + foo}
但这失败了(我发现最简单的方法来举例说明这个问题):
// not in a closure, but raises FS0419
let myObj =
{ new obj() with override this.ToString() = () |> base.ToString }
我使用的是 object 表达式而不是具有继承的类型声明,并且我尝试通过构建自定义 NUnit 约束来创建新的 FsUnit 约束。这是显示我遇到的问题的简化版本:
let EndsWithIgnoreWhitespaceContraint expectedResult =
{ new EndsWithConstraint(expectedResult) with
override __.ApplyTo<'T> (actual: 'T) =
let actual = box actual
if actual :? string then
actual :?> string
|> fun s -> if isNull s then String.Empty else s
|> fun s -> s.Trim()
// error FS0419: 'base' values may only be used to make direct
// calls to the base implementations of overridden members
|> base.ApplyTo
else
exn "String expected .. bla bla..." |> raise }
// make it available to FsUnit's syntax style (overriding existing endWith)
let endWith = EndsWithIgnoreWhitespaceContraint
// using it:
" hello world " |> should endWith "world"
现在,显然不需要知道 FsUnit 就可以看到这种行为。但是我花了一天一夜的时间才意识到我被骗了,事实上直到我在 SO 上写这个问题我才看到它。
事实证明这有效:
而不是 x |> base.SomeMethod
写 base.SomeMethod x
.
我觉得这很奇怪。不确定这是错误还是功能。但是由于 |>
运算符是内联的(我用不同的运算符对其进行了测试)并且它没有创建新函数(就像 >>
那样),所以我不明白为什么会出现此错误。
事实上,我没有看到 f a
和 a |> f
之间有任何语义差异(除了优先规则等)。那么为什么会出错呢?我违反了什么规则?
最后一个想法,kvb 写道“base
不能从闭包中调用...柯里化成员自动创建闭包”,这表明这是错误的,但它编译得很好:
let myObj foo bar =
{ new obj() with override this.ToString() = base.ToString() + foo + bar}
是否有人确切知道导致或不导致此错误的原因?
首先,您误解了“base 不能在闭包中使用”的答案。它的意思是指一个闭包 捕获基本身 - 是捕获阻止了它的工作,而不是闭包本身。在您的 { new obj }
示例中, base
未被任何闭包捕获。捕获了整个对象,但 base
仅在 ToString
方法中直接使用。
为了说明,试试这个:
let myObj =
{ new obj() with override this.ToString() = (fun() -> base.ToString())()}
此代码无法编译,因为 base
正在被闭包 fun() -> base.ToString()
.
其次,将对象方法用作函数并不像人们预期的那样有效 "directly",因为 .NET 方法的表示方式与 F# 函数不同。相反,当遇到类似 let x = obj.M
的内容时,编译器会将其视为 let x = fun a -> obj.M(a)
- 即,将其包装在闭包中。
为了说明,试试这个:
let myObj =
{ new obj() with
override this.ToString() =
let f = base.ToString // Error here
f()
}
看到这是怎么回事了吗? :-)
当您通过管道输入对象方法时,编译器必须创建该闭包,然后将其传递给管道运算符。为了说明,试试这个:
let myObj =
{ new obj() with
override this.ToString() =
() |> base.ToString // Same error
}