2010-03-17 52 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社区获得了解决方案。