康王1991
2021-08-04 16:22
采纳率: 100%
浏览 26

C#通讯线程中执行AppDomain程序域动态调用

目的:是在TCP通讯的的接受消息触发时利用AppDomain程序域通过反射动态调用本地动态编译生成的一个dll,执行其中的一个方法。
问题现象:

    public interface IRemoteInterface
    {
        object Invoke(string lcMethod, object[] Parameters);
    }

    /// <summary>
    /// Factory class to create objects exposing IRemoteInterface
    /// </summary>
    public class RemoteLoaderFactory : MarshalByRefObject
    {
        private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
        public RemoteLoaderFactory() { }
        public IRemoteInterface Create(string assemblyFile, string typeName, object[] constructArgs)
        {
            return (IRemoteInterface)Activator.CreateInstanceFrom(
                     assemblyFile, typeName, false, bfi, null, constructArgs,
                     null, null, null).Unwrap();
        }

    }

问题1:当我自定义的RemoteLoaderFactory 不继承MarshalByRefObject时,

item._server.DataReceived += new ViewModel.NetWorkServer.LeafEvent.DataReceivedHandler(_server_OnReceive);

触发通讯_server_OnReceive TCP响应函数可以执行反射调用我的本地动态生成好的dll。但是 不继承MarshalByRefObject时,会导致AppDomain程序域无法卸载。

问题2:当我自定义的RemoteLoaderFactory 继承MarshalByRefObject时,
则在_server_OnReceive TCP响应函数执行反射调用我的本地动态生成好的dll时报错。
报错很奇怪:

`捕捉到 System.Runtime.Serialization.SerializationException
  HResult=-2146233076
  Message=程序集“DiagramDesigner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中的类型“MainWindow”未标记为可序列化。
  Source=mscorlib
  StackTrace:
Server stack trace: 
   在 System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
   在 System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
   在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
   在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)

提示是MainWindow未标记为可序列化,但window是不可序列化的啊。

说明下,问题2继承MarshalByRefObject,不在tcp通讯中调用而在主线程界面按钮函数中调用是不会报这个错误的。

请问我的问题在哪里,继承MarshalByRefObject的区别和在通讯响应函数中动态调用继承MarshalByRefObject的注意点。

  • 收藏

1条回答 默认 最新

  • hxycsdn9159 2021-08-04 17:50
    已采纳

    1..net程序启动的时候会默认创建一个AppDomain,例如是App1。
    2.你在App1里面去创建了新的AppDomain例如是App2。
    3.RemoteLoaderFactory的实例会在App1和App2产生代码隔离。
    4.例如你在App1里创建了RemoteLoaderFactory的实例:RemoteLoaderFactory1。
    5.如果你的RemoteLoaderFactory继承了MarshalByRefObject说明对RemoteLoaderFactory实例在App1和App2之间是使用“按引用封送”,换句话说也就是说不管你在App1还是App2调用的都是RemoteLoaderFactory1本身.反之如果没有继承那么就是另外一种“按值封送”,这种情况下你其实实在App2创建了RemoteLoaderFactory1的副本RemoteLoaderFactory2。
    6.那么从上面5得到结论,如果你最终使用的是RemoteLoaderFactory1反射创建MainWindow实例那么你的MainWindow就属于App1,反之则会用RemoteLoaderFactory2反射创建这个实例,那么你的MainWindow就属于App2。
    7.同样的两个不同App1的MainWindow也会在App2产生代码隔离。
    8.所以你在App2去调用RemoteLoaderFactory1创建的属于App1的MainWindow的势力实例的时候就会告诉你这个实例是跨应用程序域调用,如果想要调用的话就要打上[Serializable]特性。
    所以你可以试试下面的方法在MainWindow上面打上Serializable标签:
    [Serializable]
    public partial class MainWindow : Window
    但是请注意:这个Serializable是属于按值封送,也就是说你在App2里面对MainWindow 的任何操作都是对App1里面MainWindow的副本做操作,不会影响原先App1的实例。

    已采纳该答案
    打赏 评论

相关推荐 更多相似问题