第三方库的Unity / Monotouch / C#设置委托中的JIT编译方法错误

时间:2012-08-20 14:43:31

标签: c# ios mono xmpp unity3d

我正在尝试在Unity / Monotouch / C#中为iOS for facebook创建一个chatclient。我收到以下错误

ExecutionEngineException: Attempting to JIT compile method '(wrapper managed-to-native) 
System.Threading.Interlocked:CompareExchange  
(System.EventHandler`1<Matrix.EventArgs>&,System.EventHandler`1<Matrix.EventArgs>,
System.Eve ntHandler`1<Matrix.EventArgs>)' while running with --aot-only.

  at Matrix.Net.BaseSocket.add_OnConnect (System.EventHandler`1 value) [0x00000]
in <filename unknown>:0 
  at Matrix.XmppStream..ctor (StreamType type) [0x00000] in <filename unknown>:0 
  at Matrix.Xmpp.Client.XmppClient..ctor () [0x00000] in <filename unknown>:0 
  at TestFacebook.setup () [0x00000] in <filename unknown>:0 
  at TestFacebook.Start () [0x00000] in <filename unknown>:0 

(Filename:  Line: -1)

当我尝试连接XMPP框架中的一个委托时。这是可能导致它的代码:

xmppClient.OnBeforeSasl += this.xmppClient_OnBeforeSasl;

委托方法:

public void xmppClient_OnBeforeSasl(object sender, Matrix.Xmpp.Sasl.SaslEventArgs e)
    { ... }

还尝试在没有任何结果的情况下更改API可比性级别顶级.NET 2.0。将xmppClient_OnBeforeSasl方法设置为静态也无济于事。它在Unity中运行良好,但在iOS设备上运行时崩溃。

3 个答案:

答案 0 :(得分:0)

原来Matrix不支持iOS :(

答案 1 :(得分:0)

在尝试在Unity项目中使用之前,您需要删除agsXMPP库中的所有事件使用。我确实使用了agsXMPP进行了一些修改,看起来它的工作正常。

以下是补丁的一些见解(这不是一个很好的方法):

查找并删除库项目中的所有事件关键字(将Event类取消,这是另一回事)然后替换(+ =)

xmppClient.OnBeforeSasl += this.xmppClient_OnBeforeSasl;

by(=)

xmppClient.OnBeforeSasl = this.xmppClient_OnBeforeSasl;

因为 OnBeforeSasl 现在是一个委托,而不是一个事件,你不能用这个注册多个处理程序。

但无论如何,这是一种工作,您可以通过添加addEventListener / removeEventListeners来扩展它,并使用一个委托数组而不是一个。

我确实按照这种方式行事,而且只是试一试!

答案 2 :(得分:0)

以下堆栈帧导致此错误:

at Matrix.Net.BaseSocket.add_OnConnect (System.EventHandler`1 value) [0x00000]

add_OnConnect 方法是用于注册事件的编译器生成方法。在较新版本的Microsoft C#编译器中更改了生成此方法的方式,该编译器使用 Interlocked.CompareExchange 的通用版本以获得更好的性能和线程安全性。

因此,请检查您所获得的XMPP二进制文件是否是由最近的一些Visual Studio版本构建的。

Interlocked.CompareExchange 的问题在于此方法的通用版本无法在具有可接受性能的纯C#中实现。因此JIT遭到黑客攻击。当它读取 Interlocked.CompareExchange&lt; T&gt; 的正文时,它只会触发JIT进程并生成以下IL:

ldarg.0 
ldarg.1
ldarg.2
call System.Threading.Interlocked::CompareExchange(ref Object, Object, Object)
ret

所以这个方法永远不会被AOT编译,并且总是触发一个JIT进程,因为iOS不允许代码生成,所以会失败。

如果源代码可用,请尝试通过使用MonoDevelop重建包含事件注册的二进制文件来解决问题。