Passing collection objects back and forth between

2019-07-21 18:59发布

问题:

The following sample is based on "Passing values back and forth appdomains", where Marc Gravell kindly provided a very good answer to a question about .Net remoting between appdomains. What I've done is extended it in a (very naive?) expectation that it should also work for an array of strings.

The problem is that it only works one way - the created appdomain can access the array, but only readonly. What I'd like is to get the updated array elements back in the original appdomain too. I'd even like to do this with List<> and Dictionary<> objects. Is this possible?

using System;

namespace StackoverflowSample
{
   class MyBoundaryObject : MarshalByRefObject
   {
      public void SomeMethod(AppDomainArgs ada)
      {
         Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "; executing");
         ada.MyString = "working!";
         ada.MyStringArray[0] = "working!";
         string s = ada.MyStringArray[0];  // s is assigned value "a"!!!
      }
   }


   public class AppDomainArgs : MarshalByRefObject
   {
      public string MyString { get; set; }
      public string[] MyStringArray { get; set; }
   }


   static class Program
   {
      static void Main()
      {
         AppDomain domain = AppDomain.CreateDomain("Domain666");
         MyBoundaryObject boundary = (MyBoundaryObject)
              domain.CreateInstanceAndUnwrap(
                 typeof(MyBoundaryObject).Assembly.FullName,
                 typeof(MyBoundaryObject).FullName);

         AppDomainArgs ada = new AppDomainArgs();
         ada.MyString = "abc";
         ada.MyStringArray = new string[] { "a", "b" };
         Console.WriteLine("Before: " + ada.MyString + " " + ada.MyStringArray[0]);

         boundary.SomeMethod(ada);

         Console.WriteLine("After: " + ada.MyString + " " + ada.MyStringArray[0]);
         Console.ReadKey();
         AppDomain.Unload(domain);
      }
   }
}

回答1:

Sometime back i have this requirement too of returning the updated list back to Main AppDomain and i solved it using a workaround of creating a new instance of a List and assign the desired values. This should work for you -

ada.MyStringArray = new string[] { "working!", "b" };
string s = ada.MyStringArray[0];  // s will be assigned value "working!"!!!

UPDATE

I guess you have to clone the instance and instantiate a new instance before returning from remote method. Reasons for the which it is working for simple string is -

Strings are immutable i.e. every time you initialize it with different value, a new instance is created for it behind the scenes somewhat like new String(). Hence, the update is visible in other appDomain.

I tried this small thing with StringBuilder which are mutable i.e new instance is not created for them when you change the content of the object.

public class AppDomainArgs : MarshalByRefObject
{
    public StringBuilder MyStringBuilder { get; set; }
}

public void SomeMethod(AppDomainArgs ada)
{
    Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "; executing");
    ada.MyString = "working!";
    ada.MyStringBuilder.Append(" working!");
}

Now, see the output -

Console.WriteLine("Before: " + ada.MyString + " " + ada.MyStringArray[0] + " " + 
                      ada.MyStringBuilder);    
boundary.SomeMethod(ada);    
Console.WriteLine("After: " + ada.MyString + " " + ada.MyStringArray[0] + " "
                      ada.MyStringBuilder);

You will see that StringBuilder object is unchanged. Ideally, its value should be "a working!" but still the value is "a".