c# - 跨 Appdomains 传递对象

标签 c# ironpython appdomain

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

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

我如何从 C# 中序列化 python 对象,或者是否有任何其他方法来解决这种情况。

更新

更深入地了解问题。如果我实例化我在默认应用程序域中访问 python 方法的类,然后将实例传递给创建的应用程序域,则不会出现上述问题。另一方面,当我实例化在创建的应用程序域中访问 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);
    }
}

最佳答案

现在这对我有用。

问题是我试图将对象从远程域返回到本地域。 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 社区获得了解决方案。

关于c# - 跨 Appdomains 传递对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2459759/

相关文章:

python-2.7 - 使用IronPython访问Pandas库

python - 在 IronPython 中创建自定义 WPF 控件 : a control made up out of standard controls

c# - 尝试访问已卸载的应用程序域(调用 AzMan)

c# - 具有多泛型问题的 AppDomain.DoCallBack()

c# 以编程方式定义 treeview 属性

c# - 将 DBNull.Value 和空文本框值传递给数据库

c# - C# 中的内部属性 setter

c# - 从代码更改 CSS 类

.net - 使用 .net 库自动执行任务的最佳技术是什么?

.net - 将程序集加载到另一个 AppDomain 和类型检查