2010-03-17 77 views
2

我在跨AppDays傳遞對象時遇到問題。在進一步調查中,我發現問題是由於IronPython對象未被序列化。這個IronPython對象是從.NET基類派生的。 .NET基類是從MarshalByRefObj派生的。跨應用程序域傳遞對象

讓我解釋一下我的環境。我的C#應用​​程序中嵌入了IronPython。強制IronPython中的每個類都繼承.NET基類,稱爲ClassA。 ClassA從MarshalByRefObj派生,因爲我需要將此類的一個實例傳遞給另一個AppDomain。我創建一個新的appdomain並將ClassA的實例傳遞給此AppDomain。當通過ClassA的實例調用python類中的方法時,我得到一個異常,提到在Assembly'IronPython,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = 31bf3856ad364e35'中鍵入'IronPython.Runtime.Types.PythonType'標記爲可序列化「

如何從C#序列化python對象,或者是否有任何其他方法來解決這種情況。

更新

更深入地瞭解這個問題。如果我實例化我在默認appdomain中訪問python方法的類,然後將該實例傳遞給創建的appdomain,那麼上面提到的問題是看不到的。另一方面,當我實例化在創建的appdomain中訪問python方法的類,然後訪問python方法時,將拋出序列化異常。

我看到解決此問題的一種方法是我修改IronPython源代碼以序列化所需的類型。有沒有其他辦法可以解決這個問題。

這裏是一個示例代碼重現例外,我遇到

using System; 
using Microsoft.Scripting; 
using IronPython.Hosting; 
using Microsoft.Scripting.Hosting; 

class Foo 
{ 
    public static void Main(string[] args) 
    { 
     AppDomain ad = AppDomain.CreateDomain("foo"); 
     var engine = Python.CreateEngine(ad); 
     engine.Runtime.LoadAssembly(typeof(MbrBase).Assembly); 

     var code = engine.CreateScriptSourceFromString(@" 
import MbrBase 
class C(MbrBase): 
    pass 

a = C() 
", SourceCodeKind.Statements); 

     var scope = engine.CreateScope(); 
     code.Execute(scope); 

     Console.WriteLine("Trying to do it... {0}", 
AppDomain.CurrentDomain.Id); 
     MbrBase mbr = (MbrBase)scope.GetVariable("a"); 

     string isSubClassCode = String.Format("issubclass({0},{1})", "C", 
"MbrBase"); 
     ScriptSource script = 
engine.CreateScriptSourceFromString(isSubClassCode, 
SourceCodeKind.Expression); 
     bool result = (bool)script.Execute(scope); 

     if (result == true) 
     { 
      ObjectOperations ops = engine.Operations; 

      object subClass = scope.GetVariable("C"); 
      object instance = ops.Call(subClass); 

      mbr = instance as MbrBase; 
     } 

     mbr.DoItVirtually(); 
     mbr.DoIt(); 
     Console.ReadKey(); 
    } 
} 

public class MbrBase : MarshalByRefObject 
{ 
    public virtual void DoItVirtually() 
    { 
     Console.WriteLine("Did it virtually {0}", AppDomain.CurrentDomain.Id); 
    } 

    public void DoIt() 
    { 
     Console.WriteLine("Did it {0}", AppDomain.CurrentDomain.Id); 
    } 
} 
+0

@Mustaq如果您有關於您的問題的其他信息,請編輯您的原始問題並添加該信息。提問者一般不應該在這個問題下面發佈任何內容,這就是答案的出處。 – Sampson 2010-03-26 16:09:40

回答

2

現在,這對我的作品。

問題是我試圖將對象從遠程域返回到本地域。 ObjectOperations有一套重載ObjectHandles的方法,還有一些方法返回ObjectHandles來處理遠程應用程序域中的對象。如果上面的代碼被修改爲下面的代碼,它就可以工作。

地址:使用System.Runtime.Remoting

 var subClass = scope.GetVariableHandle("C"); // get back a handle 
     var instance = ops.Invoke(subClass, new ObjectHandle[0]); // invoke the handle to create an instance 

     mbr = instance.Unwrap() as MbrBase; // now we know we have an MBR and we can unwrap it to our local side 

附:我從Iron Python社區獲得瞭解決方案。