1

您好我的应用程序由一些“内核”和模块组成,这些模块动态加载到自己的 AppDomain 并根据需要卸载。但我不明白一件事。我将发布一个与我所拥有的类似的简单代码。

有一个“接口”类,其中包含许多虚拟钩子和属性以及一些自己的功能:

[Serializable()]
public abstract class Module : MarshalByRefObject
{
    public static List<Module> module = new List<Module>();
    public string Name = "";
    public string Version = "unknown";
    public DateTime Date = DateTime.Now;

    Module()
    {
        lock(module)
        {
            module.Add(this);
        }
    }

    ~Module()
    {
        Exit();
        lock (module)
        {
            if (module.Contains(this))
            {
                module.Remove(this);
            }
        }
        core.Log("Module was unloaded: " + this.Name);
    }

    public virtual void Hook1()
    {
      // by default ignore
    }
}

each module is a new project that is referenced to core and creates a new class that is inherited from Module and extends the "kernel". Some events are hooked in a way that I go in a loop through Module.module List that is supposed to contain all existing loaded instances and call the respective hook in that one. This works fine if I am in one AppDomain. But if I use a separate AppDomain for module it seems that the memory of original Domain get copied to new domain and when I call the constructor of new instance, it doesn't insert itself to static array in Module.module of original domain, but it insert itself to Module.module in a new domain. That means, in core I still have 0 modules in Module.module. I managed to fix this by creating another function that register module instead of what I had in constructor. But still it happens that sometimes I access the memory in original domain and sometime the memory in new domain of module. This causes troubles. How can I make it sure that I always access the same memory from kernel and from module as well?

Example of what I need to do is:

  • Pass pointer to instance of a class which is in memory of AppDomain A to a hook of module living in AppDomain B
  • let the module change something in that class (in memory of domain A, not in B)
4

2 回答 2

0

Statics are not shared by AppDomains! Each AppDomain will have a different list of modules.

于 2012-11-15T14:21:10.060 回答
0

You'll need to be able to instantiate proxies to each of the target domains and pass them across app domain boundaries. I would create a controller pattern that manages all the modules inside each remote domain from the current one and passes proxies across the domain boundaries when you need to manipulate data.

Here's an example of how to manipulate an object across multiple domains with the AppDomainToolkit.

namespace ConsoleApplication1
{
    using System;
    using System.Threading.Tasks;
    using AppDomainToolkit;
    using System.Collections.Generic;

    class Program
    {
        static void Main(string[] args)
        {
            using (var context1 = AppDomainContext.Create())
            using (var context2 = AppDomainContext.Create())
            using (var context3 = AppDomainContext.Create())
            {
                var pizzaInContext1 = Remote<Pizza>.CreateProxy(context1.Domain, "Hawaiian");

                // manipulate object from current app domain
                pizzaInContext1.RemoteObject.AddTopping(new Topping("Cheese"));

                // manipulate object from context 2
                RemoteAction.Invoke(
                    context2.Domain,
                    pizzaInContext1.RemoteObject,
                    new Topping("Pineapple"),
                    (pizza, topping) =>
                    {
                        pizza.AddTopping(topping);
                    });

                // manipulate object, adding info from context 3
                RemoteAction.Invoke(
                    context3.Domain,
                    pizzaInContext1.RemoteObject,
                    (pizza) =>
                    {
                        pizza.AddTopping(new Topping("Ham"));
                    });

                Console.WriteLine(pizzaInContext1.RemoteObject.ToString());
            }

            Console.ReadKey();
        }
    }

    class Pizza : MarshalByRefObject
    {
        private readonly IList<Topping> toppings;

        public Pizza(string name)
        {
            this.Name = name;
            this.toppings = new List<Topping>();
        }

        public string Name { get; private set; }

        public void AddTopping(Topping topping)
        {
            this.toppings.Add(topping);
        }

        public override string ToString()
        {
            var pizza = this.Name + " with toppings: [";
            for (int i = 0; i < this.toppings.Count; i++)
            {
                pizza += this.toppings[i].Name;
                if (i < this.toppings.Count - 1)
                {
                    pizza += ",";
                }
            }
            pizza += "]";
            return pizza;
        }
    }

    [Serializable]
    class Topping
    {
        public Topping(string name)
        {
            this.Name = name;
        }

        public string Name { get; private set; }

        public override string ToString()
        {
            return this.Name;
        }
    }
}

Output

于 2012-11-26T02:13:30.923 回答