我在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);
}
}
答案 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社区获得了解决方案。