在Appdomains中传递对象

时间:2010-03-17 03:37:45

标签: c# ironpython appdomain

我在Appdomains上传递对象时遇到问题。在进一步调查中,我发现问题是由于IronPython对象未被序列化。此IronPython对象派生自.NET基类。 .NET基类派生自MarshalByRefObj。

让我解释一下我的环境。我在我的C#应用​​程序中嵌入了IronPython。强制要求IronPython中的每个类都继承.NET基类,即ClassA。 ClassA派生自MarshalByRefObj,因为我需要将此类的实例传递给另一个appdomain。我创建一个新的appdomain并将ClassA的实例传递给此Appdomain。通过ClassA实例调用python类中的方法时,我得到一个例外,提到在程序集'IronPython中的类型'IronPython.Runtime.Types.PythonType',Version = 2.0.0.0,Culture = neutral,PublicKeyToken = 31bf3856ad364e35'不是标记为可序列化的“

如何从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);
    }
}

1 个答案:

答案 0 :(得分: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

P.S。我从Iron Python社区获得了解决方案。