TWi*_*ars 7 c# f# interop access-violation nullreferenceexception
我有以下C#类
public class BadClass
{
public BadClass(int? bad = 1)
{
}
}
public class GoodClass
{
public GoodClass(int? good = null)
{
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它们都具有可选的可空参数作为其构造函数的一部分,唯一的区别是BadClass将参数default设置为null以外的其他值.
如果我尝试在F#中创建这些类的实例,这就是我得到的:
这很好用:
let g = GoodClass()
Run Code Online (Sandbox Code Playgroud)
这会抛出NullReferenceException:
let b = BadClass()
Run Code Online (Sandbox Code Playgroud)
这会引发AccessViolationException
let asyncB = async { return BadClass() } |> Async.RunSynchronously
Run Code Online (Sandbox Code Playgroud)
知道为什么会这样吗?
编辑
使用ILSpy对其进行反编译,这是F#的输出
C#类位于一个名为InteopTest的程序集中[原文如此]
ILSpy到C#
GoodClass g = new GoodClass(null);
BadClass b = new BadClass(1);
FSharpAsyncBuilder defaultAsyncBuilder = ExtraTopLevelOperators.DefaultAsyncBuilder;
FSharpAsync<BadClass> fSharpAsync = defaultAsyncBuilder.Delay<BadClass>(new Program.asyncB@10(defaultAsyncBuilder));
FSharpAsync<BadClass> computation = fSharpAsync;
BadClass asyncB = FSharpAsync.RunSynchronously<BadClass>(computation, null, null);
FSharpFunc<string[], Unit> fSharpFunc = ExtraTopLevelOperators.PrintFormatLine<FSharpFunc<string[], Unit>>(new PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit, string[]>("%A"));
fSharpFunc.Invoke(argv);
return 0;
Run Code Online (Sandbox Code Playgroud)
这就是IL
.method public static
int32 main (
string[] argv
) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2050
// Code size 92 (0x5c)
.maxstack 5
.entrypoint
.locals init (
[0] class [InteopTest]InteopTest.GoodClass g,
[1] valuetype [mscorlib]System.Nullable`1<int32>,
[2] class [InteopTest]InteopTest.BadClass b,
[3] class [InteopTest]InteopTest.BadClass asyncB,
[4] class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsync`1<class [InteopTest]InteopTest.BadClass>,
[5] class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsyncBuilder builder@,
[6] class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsync`1<class [InteopTest]InteopTest.BadClass>,
[7] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string[], class [FSharp.Core]Microsoft.FSharp.Core.Unit>,
[8] string[]
)
IL_0000: nop
IL_0001: ldloca.s 1
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloc.1
IL_000a: newobj instance void [InteopTest]InteopTest.GoodClass::.ctor(valuetype [mscorlib]System.Nullable`1<int32>)
IL_000f: stloc.0
IL_0010: ldc.i4.1
IL_0011: newobj instance void [InteopTest]InteopTest.BadClass::.ctor(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0016: stloc.2
IL_0017: call class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsyncBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_DefaultAsyncBuilder()
IL_001c: stloc.s builder@
IL_001e: ldloc.s builder@
IL_0020: ldloc.s builder@
IL_0022: newobj instance void Program/asyncB@10::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsyncBuilder)
IL_0027: callvirt instance class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsync`1<!!0> [FSharp.Core]Microsoft.FSharp.Control.FSharpAsyncBuilder::Delay<class [InteopTest]InteopTest.BadClass>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsync`1<!!0>>)
IL_002c: stloc.s 4
IL_002e: ldloc.s 4
IL_0030: stloc.s 6
IL_0032: ldloc.s 6
IL_0034: ldnull
IL_0035: ldnull
IL_0036: call !!0 [FSharp.Core]Microsoft.FSharp.Control.FSharpAsync::RunSynchronously<class [InteopTest]InteopTest.BadClass>(class [FSharp.Core]Microsoft.FSharp.Control.FSharpAsync`1<!!0>, class [FSharp.Core]Microsoft.FSharp.Core.FSharpOption`1<int32>, class [FSharp.Core]Microsoft.FSharp.Core.FSharpOption`1<valuetype [mscorlib]System.Threading.CancellationToken>)
IL_003b: stloc.3
IL_003c: ldstr "%A"
IL_0041: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string[], class [FSharp.Core]Microsoft.FSharp.Core.Unit>, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, string[]>::.ctor(string)
IL_0046: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string[], class [FSharp.Core]Microsoft.FSharp.Core.Unit>>(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
IL_004b: stloc.s 7
IL_004d: ldarg.0
IL_004e: stloc.s 8
IL_0050: ldloc.s 7
IL_0052: ldloc.s 8
IL_0054: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string[], class [FSharp.Core]Microsoft.FSharp.Core.Unit>::Invoke(!0)
IL_0059: pop
IL_005a: ldc.i4.0
IL_005b: ret
} // end of method Program::main
Run Code Online (Sandbox Code Playgroud)
对我来说,这看起来像是F#编译器中的一个错误.如果你写一些额外的C#:
public class OtherClass
{
private static BadClass _bc = new BadClass();
}
Run Code Online (Sandbox Code Playgroud)
看看IL,你会看到这个:
// push 1 on the stack
IL_0000: ldc.i4.1
// call Nullable<int32> constructor, leaving object on stack
IL_0001: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
// call BadClass constructor with int?
IL_0006: newobj instance void Nullabool.BadClass::.ctor(valuetype [mscorlib]System.Nullable`1<int32>)
// store in _bc
IL_000b: stsfld class Nullabool.BadClass Nullabool.OtherClass::_bc
Run Code Online (Sandbox Code Playgroud)
其中明确地将Nullable`1实例化为1.
而b的F#代码最终会像这样:
// push a 1 on the stack
IL_0016: ldc.i4.1
// call BadClass constructor with 1 - this fails IL verification
IL_0017: newobj instance void [Nullabool]Nullabool.BadClass::.ctor(valuetype [mscorlib]System.Nullable`1<int32>)
Run Code Online (Sandbox Code Playgroud)
它留下int堆栈而不是int?.当我尝试运行此代码时,由于类型不匹配,我收到IL验证错误.
| 归档时间: |
|
| 查看次数: |
1040 次 |
| 最近记录: |