2015-02-27 6 views
2

Я хочу получить доступ к статическому списку Class2, который будет создан в Class1.Получить статический список из AppDomain

Class1 загружается в AppDomain и загружает Class2 в другой AppDomain. Но если я хочу получить доступ к статическому списку в классе2, я получаю два разных списка.

Я думаю, что мне нужно получить доступ к тому же AppDomain в Class1, чтобы получить Class2, но как я могу достичь этого, если объекты Class1 находятся в разных AppDomains?

Кстати: Не нужно класть Class2 в другой AppDomain, но я думал, что смогу получить тот же объект, если я это сделаю.

Вот мой код:

public class Class1 : MarshalByRefObject 
{ 
    Class2 class2; 

    public Class2 Class2 
    { 
     get { return class2; } 
     set { class2 = value; } 
    } 
    public Class1() 
    { 
     AppDomain adc2 = AppDomain.CreateDomain("adc2"); 
     class2 = (Class2)adc2.CreateInstanceAndUnwrap(typeof(Class2).Assembly.FullName, typeof(Class2).FullName); 
    } 
} 
public class Class2 : MarshalByRefObject 
{ 
    static List<int> myIntegers = new List<int>(); 

    public static List<int> MyIntegers 
    { 
     get { return Class2.myIntegers; } 
     set { Class2.myIntegers = value; } 
    } 
    public void AddInteger(int integer) 
    { 
     myIntegers.Add(integer); 
    } 
    public override string ToString() 
    { 
     StringBuilder sb = new StringBuilder(); 
     foreach (int integer in myIntegers) 
     { 
      sb.AppendLine(integer.ToString()); 
     } 
     return sb.ToString(); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Type type1 = typeof(Class1); 
     AppDomain ad1 = AppDomain.CreateDomain("ad1"); 
     Class1 ad1t1 = (Class1)ad1.CreateInstanceFromAndUnwrap(type1.Assembly.Location, type1.FullName); 

     AppDomain ad2 = AppDomain.CreateDomain("ad2"); 
     Class1 ad2t1 = (Class1)ad2.CreateInstanceFromAndUnwrap(type1.Assembly.Location, type1.FullName); 

     ad1t1.Class2.AddInteger(0); 
     ad2t1.Class2.AddInteger(1); 
     Console.WriteLine(ad1t1.Class2.ToString()); //Output: 0 
     Console.WriteLine(ad2t1.Class2.ToString()); //Output: 1 
     // 
     Console.ReadKey(); 
    } 
} 

Редактировать

Ok я узнал, что мой плагин погрузчик виноват. Может кто-нибудь сказать, почему вы не можете работать через приложения, если вы будете использовать разные Pluginloaders (или хотя бы один загрузчик)?

Если все файлы находятся в одной сборке, он будет работать (приращение равно 3). В моем сценарии (много разных сборок) я получаю только 1,1,1

Если кому-то нужна дополнительная информация, чтобы помочь мне, не стесняйтесь просить об этом.

Пример 1 (каждый экземпляр рассчитывать на себя):

в сборе: Main

PluginLoader.PluginLoader<IPlugin> pluginLoader1 = new PluginLoader.PluginLoader<IPlugin>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))); 
IPlugin cl1 = pluginLoader1.Activate("MyLibrary.dll", "MyLibrary.Class1"); 
PluginLoader.PluginLoader<IPlugin> pluginLoader2 = new PluginLoader.PluginLoader<IPlugin>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))); 
IPlugin cl3 = pluginLoader2.Activate("MyLibrary2.dll", "MyLibrary2.Class3"); 
//Increment() increases a static variable starting by 0 
cl1.Increment(); 
Console.WriteLine(cl1.ToString()); //Output: 1 
cl3.Increment(); 
Console.WriteLine(cl3.ToString()); //Output: 1 

ClassLibrary2.Class2 class2 = new ClassLibrary2.Class2(); 
class2.Increment(); 
Console.WriteLine(class2.ToString()); //Output: 1 

Сборка: ClassLibrary2

[Serializable] 
public class Class2 : IPlugin 
{ 
    public Class2() { } 

    public override string ToString() 
    { 
     return incrementer.ToString(); 
    } 
    static int incrementer = 0; 
    public void Increment() 
    { 
     incrementer++; 
    } 
} 

Сборка: MyLibrary

public class Class1 : MarshalByRefObject, IPlugin 
{ 
    Class2 class2; 

    public Class2 Class2 
    { 
     get { return class2; } 
     set { class2 = value; } 
    } 
    public Class1() 
    { 
     PluginLoader.PluginLoader<Class2> pluginLoader = new PluginLoader.PluginLoader<Class2>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))); 
     class2 = pluginLoader.Activate("ClassLibrary2.dll", "ClassLibrary2.Class2"); 
     //AppDomain adc2 = AppDomain.CreateDomain("adc2"); 
     //class2 = (Class2)adc2.CreateInstanceAndUnwrap(typeof(Class2).Assembly.FullName, typeof(Class2).FullName); 
    } 
    public void Increment() 
    { 
     this.class2.Increment(); 
    } 
    public override string ToString() 
    { 
     return AppDomain.CurrentDomain.FriendlyName+": "+ this.class2.ToString(); 
    } 
} 

АССАМБЛЕЯ LY: MyLibrary2

public class Class3 : MarshalByRefObject, IPlugin 
{ 
    Class2 class2; 

    public Class2 Class2 
    { 
     get { return class2; } 
     set { class2 = value; } 
    } 
    public Class3() 
    { 
     PluginLoader.PluginLoader<Class2> pluginLoader = new PluginLoader.PluginLoader<Class2>(new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))); 
     class2 = pluginLoader.Activate("ClassLibrary2.dll", "ClassLibrary2.Class2"); 
     //AppDomain adc2 = AppDomain.CreateDomain("adc2"); 
     //class2 = (Class2)adc2.CreateInstanceAndUnwrap(typeof(Class2).Assembly.FullName, typeof(Class2).FullName); 
    } 
    public void Increment() 
    { 
     this.class2.Increment(); 
    } 
    public override string ToString() 
    { 
     return AppDomain.CurrentDomain.FriendlyName + ": " + this.class2.ToString(); 
    } 
} 

Сборка: PluginInterface

public interface IPlugin 
{ 
    void Increment(); 
} 

Сборка: PluginLoader

public class PluginLoader<T> where T : IPlugin 
{ 
    //Here are placed all Fields 
    #region Fields 
    string path; 
    System.AppDomain appDomain; 
    #endregion 

    //Here are placed all Properties 
    #region Properties 
    public List<KeyValuePair<String, String>> Plugins 
    { 
     get { return (List<KeyValuePair<String, String>>)appDomain.GetData("Plugins"); } 
    } 
    #endregion 

    //Here are placed all Constructors 
    #region Constructors 
    public PluginLoader(DirectoryInfo path) 
    { 
     this.path = path.FullName; 
     if (!path.Exists) 
      path.Create(); 
     AppDomainSetup appDomainSetup = new AppDomainSetup(); 
     appDomainSetup.AppDomainInitializer = new AppDomainInitializer(GetInterfaceTypes); 
     appDomainSetup.AppDomainInitializerArguments = new string[] { this.path }; 
     appDomain = AppDomain.CreateDomain(typeof(T).Name, null, appDomainSetup); 
    } 
    #endregion 

    #region Methods 
    private static void GetInterfaceTypes(string[] args) 
    { 
     AppDomain appDomain = System.AppDomain.CurrentDomain; 
     string[] files = Directory.GetFiles(args[0], "*.dll", SearchOption.AllDirectories); 
     List<KeyValuePair<String, String>> infos = new List<KeyValuePair<String, String>>(); 
     foreach (string file in files) 
     { 
      try 
      { 
       Assembly asm = Assembly.LoadFrom(file); 
       foreach (Type type in asm.GetTypes()) 
       { 
        if (typeof(T).IsAssignableFrom(type)) 
         infos.Add(new KeyValuePair<string, string>(file, type.FullName)); 
       } 
      } 
      catch (Exception ex) 
      { 
      } 
     } 
     appDomain.SetData("Plugins", infos); 
    } 
    public virtual T Activate(String assemblyFile, String type, params object[] args) 
    { 
     try 
     { 
      T instance = (T)this.appDomain.CreateInstanceFromAndUnwrap(Path.Combine(this.path, Path.GetFileName(assemblyFile)), type, args); 
      return instance; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

    #endregion 
} 

Пример 2 (Каждый экземпляр подсчитывают же приращение переменной):

Поместить все классы один сборка.

public interface IPlugin 
{ 
    void Increment(); 
} 
[Serializable] 
public class Class1 : IPlugin 
{ 
    public Class1() { } 
    static int incrementer = 0; 
    public void Increment() 
    { 
     incrementer++; 
    } 
    public override string ToString() 
    { 
     return incrementer.ToString(); 
    } 
} 
class PluginLoader<T> where T : IPlugin 
{ 
    //Here are placed all Fields 
    #region Fields 
    string path; 
    System.AppDomain appDomain; 
    #endregion 

    //Here are placed all Properties 
    #region Properties 
    public List<KeyValuePair<String, String>> Plugins 
    { 
     get { return (List<KeyValuePair<String, String>>)appDomain.GetData("Plugins"); } 
    } 
    #endregion 

    //Here are placed all Constructors 
    #region Constructors 
    public PluginLoader(DirectoryInfo path) 
    { 
     this.path = path.FullName; 
     if (!path.Exists) 
      path.Create(); 
     AppDomainSetup appDomainSetup = new AppDomainSetup(); 
     appDomainSetup.AppDomainInitializer = new AppDomainInitializer(GetInterfaceTypes); 
     appDomainSetup.AppDomainInitializerArguments = new string[] { this.path }; 
     appDomain = AppDomain.CreateDomain(typeof(T).Name, null, appDomainSetup); 
    } 
    #endregion 

    #region Methods 
    private static void GetInterfaceTypes(string[] args) 
    { 
     AppDomain appDomain = System.AppDomain.CurrentDomain; 
     string[] files = Directory.GetFiles(args[0], "*.dll", SearchOption.AllDirectories); 
     List<KeyValuePair<String, String>> infos = new List<KeyValuePair<String, String>>(); 
     foreach (string file in files) 
     { 
      try 
      { 
       Assembly asm = Assembly.LoadFrom(file); 
       foreach (Type type in asm.GetTypes()) 
       { 
        if (typeof(T).IsAssignableFrom(type)) 
         infos.Add(new KeyValuePair<string, string>(file, type.FullName)); 
       } 
      } 
      catch (Exception ex) 
      { 
      } 
     } 
     appDomain.SetData("Plugins", infos); 
    } 
    public virtual T Activate(String assemblyFile, String type, params object[] args) 
    { 
     try 
     { 
      T instance = (T)this.appDomain.CreateInstanceFromAndUnwrap(Path.Combine(this.path, Path.GetFileName(assemblyFile)), type, args); 
      return instance; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

    #endregion 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     string file = System.Reflection.Assembly.GetExecutingAssembly().Location; 
     string path = Path.GetDirectoryName(file); 

     PluginLoader<IPlugin> pluginLoader1 = new PluginLoader<IPlugin>(new DirectoryInfo(path)); 
     IPlugin cl1 = pluginLoader1.Activate(file, "AppDomainCheck.Class1"); 
     PluginLoader<IPlugin> pluginLoader2 = new PluginLoader<IPlugin>(new DirectoryInfo(path)); 
     IPlugin cl3 = pluginLoader1.Activate(file, "AppDomainCheck.Class1"); 

     cl1.Increment(); 
     Console.WriteLine(cl1.ToString()); //Output: 1 
     cl3.Increment(); 
     Console.WriteLine(cl3.ToString()); //Output: 2 

     Console.ReadKey(); 
    } 
} 
+0

Это может быть полезно для вас http://stackoverflow.com/a/9807826/1505865 –

+0

Я тоже прочитал этот комментарий, но когда я попробовал его в своем приложении, он не будет работать. Так что что-то еще не совпадает с моим примером кода (в приведенном выше примере он работает). – Mitja

+0

Извините, вставьте неправильную ссылку здесь, ваш ответ, похоже, происходит в его вопросе :) http://stackoverflow.com/q/4298913/1505865 –

ответ

3

Статические переменные ограничены текущим доменом приложения. Если у вас N разных доменов приложений, у вас есть N разных значений для статического свойства.

В C# Language Specification 5.0:

10.5.1 Статическое поле не является частью конкретного экземпляра; вместо этого он распределяется между всеми экземплярами закрытого типа (§4.4.2).Независимо от того, сколько экземпляров закрытого типа класса создано, существует только одна копия статического поля для связанного домена приложения.

+0

Если я использую сериализуемый класс вместо MarshalByRefObject, я получу копию моей статической переменной в каждом приложении. Но по моему сценарию это не работает. – Mitja

+0

В коде, который вы отправили, каждый раз, когда вы создаете новый appdomain, каждый раз, когда вы увеличиваете значение один раз на вновь созданном appdomain, результат равен 1. IMO, это поведение является нормальным. – rducom

+0

Если я поместил все файлы в одну сборку, int увеличится до 3. – Mitja

Смежные вопросы