下一次测试失败。我直接将GetType调用到函数定义,然后我也在内联函数中调用GetType。生成的类型不相等。
namespace PocTests
open FsUnit
open NUnit.Framework
module Helpers =
let balance ing gas = ing - gas
[<TestFixture>]
type ``Reflected types`` ()=
[<Test>] member x.
``test type equality with inline use`` () =
let inline (=>) f = f.GetType().FullName, f in
let fullName, fval = (=>) Helpers.balance in
Helpers.balance.GetType().FullName |> should equal (fullName)
我怎么能得到相同的类型才能“可比”。
答案 0 :(得分:5)
当您将函数用作值时,F#不会保证两个创建的对象将是“相同”。在封面下,编译器为每个实例创建一个新的闭包对象,因此即使你尝试这样的事情,你实际上也会获得false
:
balance.GetType().FullName = balance.GetType().FullName
这是预期的行为 - 当您尝试直接比较函数时,编译器会告诉您函数不满足等式约束并且无法进行比较:
> let balance ing gas = ing - gas;;
val balance : ing:int -> gas:int -> int
> balance = balance;;
error FS0001: The type '(int -> int -> int)' does not support the
'equality' constraint because it is a function type
这意味着您问题的最佳答案是您要求的内容无法完成。我认为比较函数值很可能不是一个好主意,但如果您提供更多详细信息,为什么要这样做,或许可以为您的特定问题找到更好的答案。
如果你真的想对函数值进行相等测试,那么最干净的方法可能是定义一个接口并测试普通对象的相等性:
type IFunction =
abstract Invoke : int * int -> int
let wrap f =
{ new IFunction with
member x.Invoke(a, b) = f a b }
现在,您可以将balance
函数包装在可以比较的接口实现中:
let balance ing gas = ing - gas
let f1 = wrap balance
let f2 = f1
let f3 = wrap balance
f1 = f2 // These two are the same object and are equal
f1 = f3 // These two are different instances and are not equal
答案 1 :(得分:1)
每次调用Helpers.balance
时都会创建一个新的闭包,所以
Helpers.balance.GetType().FullName |> printfn "%A" //output: "Program+main@22-1"
Helpers.balance.GetType().FullName |> printfn "%A" //output: "Program+main@23-2"
与类相似(从c#中编译的exe反编译)
[Serializable]
internal class main@22-1 : OptimizedClosures.FSharpFunc<int, int, int>
{
internal main@22-1()
{
base..ctor();
}
public override int Invoke(int ing, int gas)
{
return Program.Helpers.balance(ing, gas);
}
}