ArrayLists and TransparentProxies

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • smulz
    New Member
    • Sep 2009
    • 3

    ArrayLists and TransparentProxies

    I have an AppDomain, I CreateInstanceA ndUnwrap on this AppDomain on an object that inherits from MarshalByRefObj ect. The object that returns is a __TransparentPr oxy, it is then cast to the interface the underlying object implements. This object has an ArrayList property. I'm able to read this ArrayList just fine, list[5] returns a value. But all attempts to Add() items results in nothing happening. No exception and the item is not added.

    Does anyone know why this happens?
  • smulz
    New Member
    • Sep 2009
    • 3

    #2
    Here's an example of what I mean...



    Code:
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    
    namespace WebQuestion
    {
        interface IListInterface
        {
            ArrayList Items { get; set; }
        }
    
        class ListClass : MarshalByRefObject, IListInterface
        {
            private ArrayList items = new ArrayList{0,1,2,3,4,5};
            public ArrayList Items 
            { 
                get
                {
                    return items;
                } 
                set
                {
                    items = value;
                } 
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                AppDomain ad = AppDomain.CreateDomain("OtherAppDomain");
                IListInterface byRef = (IListInterface)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "WebQuestion.ListClass");
                foreach (object obj in byRef.Items)
                {
                    Console.WriteLine(obj);
                }
    
                Console.WriteLine("Item Count before Add(): " + byRef.Items.Count);  //Items.Count == 6
                byRef.Items.Add("Item at index 6");
                Console.WriteLine("Item Count after Add(): " + byRef.Items.Count);  //Items.Count == 6, still
    
                try
                {
                    Console.WriteLine("Getting item at Items[6]...");
                    Console.WriteLine(byRef.Items[6]);  //throw exception
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }

    Comment

    • cloud255
      Recognized Expert Contributor
      • Jun 2008
      • 427

      #3
      Hmmm, this is very interesting. It appears that the issue arises due to the protection level of the items object. Have a look at the following:

      Code:
      interface IListInterface
           {
               ArrayList Items { get; set; }
               void AddItem(object valueToAdd); //method to access the private item variable
           }
        
           class ListClass : MarshalByRefObject, IListInterface
           {
           	
           	private ArrayList items = new ArrayList{0,1,2,3,4,5};
               public ArrayList Items 
               { 
                   get
                   {
                       return items;
                   } 
                   set
                   {
                       items = value;
                   } 
               }
               
              //method calls add function of the private variable
               public void AddItem(object valueToAdd)
               {
               	if(valueToAdd != null)
               		items.Add(valueToAdd);
               }
           }
        
           class Program
           {
               static void Main(string[] args)
               {
                   AppDomain ad = AppDomain.CreateDomain("OtherAppDomain");
                   IListInterface byRef = (IListInterface)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "b2.ListClass");
                   
                   foreach (object obj in byRef.Items)
                   {
                       Console.WriteLine(obj);
                   }
        
                   Console.WriteLine("Item Count before Add(): " + byRef.Items.Count);  //Items.Count == 6
                   
                   //add the value
                   byRef.AddItem("Item at index 6");
                   Console.WriteLine("Item Count after Add(): " + byRef.Items.Count);  //Items.Count == 7 now
        
                   try
                   {
                       Console.WriteLine("Getting item at Items[6]...");
                       Console.WriteLine(byRef.Items[6]);  //exception is gone
                   }
                   catch (Exception e)
                   {
                       Console.WriteLine(e.Message);
                   }
                   Console.ReadKey();
               }
           }
      Only the public Items member can be accessed so you add an object to the Items list but when you call the get method of Items, the private items variable is returned. The private items variable has never had an object added to it, thus it still only contains the original 6 members. I may be mistaken here, but that is my reasoning of the situation...

      Comment

      • Plater
        Recognized Expert Expert
        • Apr 2007
        • 7872

        #4
        I've never seen the SET section required for a collection object. Do to the nature of it, I believe just the GET is all that is required.
        Maybe it will help?
        I've never had a problem doing it (without an interface), but have never tried it with an interface

        Comment

        • smulz
          New Member
          • Sep 2009
          • 3

          #5
          Thanks for your reply cloud. But can you explain that the same behavior happens when I'm directly modifying the public variable?

          Code:
          using System;
          using System.Collections;
          using System.Collections.Generic;
          using System.Linq;
          using System.Reflection;
          using System.Text;
          
          namespace WebQuestion
          {
              interface IListInterface
              {
                  ArrayList Items { get; set; }
              }
          
              class ListClass : MarshalByRefObject, IListInterface
              {
                  public ArrayList publicItems = new ArrayList { 0, 1, 2, 3, 4, 5 };
                  private ArrayList items = new ArrayList { 0, 1, 2, 3, 4, 5 };
                  public ArrayList Items 
                  { 
                      get
                      {
                          return items;
                      } 
                      set
                      {
                          items = value;
                      } 
                  }
              }
          
              class Program
              {
                  static void Main(string[] args)
                  {
                      AppDomain ad = AppDomain.CreateDomain("OtherAppDomain");
                      IListInterface byRef = (IListInterface)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "WebQuestion.ListClass");
                      foreach (object obj in byRef.Items)
                      {
                          Console.WriteLine(obj);
                      }
          
                      Console.WriteLine("Item Count before Add(): " + byRef.Items.Count);  //Items.Count == 6
                      byRef.Items.Add("Item at index 6");
                      Console.WriteLine("Item Count after Add(): " + byRef.Items.Count);   //Items.Count == 6, still
          
                      try
                      {
                          Console.WriteLine("Getting item at Items[6]...");
                          Console.WriteLine(byRef.Items[6]);  //throw exception
                      }
                      catch (Exception e)
                      {
                          Console.WriteLine(e.Message);
                      }
          
                      ListClass listClass = (ListClass) byRef;
          
                      foreach (object obj in listClass.publicItems)
                      {
                          Console.WriteLine(obj);
                      }
          
                      Console.WriteLine("Item Count before Add(): " + listClass.publicItems.Count);  //publicItems.Count == 6
                      listClass.publicItems.Add("Item at index 6");
                      Console.WriteLine("Item Count after Add(): " + listClass.publicItems.Count);   //publicItems.Count == 6, still
          
                      try
                      {
                          Console.WriteLine("Getting item at publicItems[6]...");
                          Console.WriteLine(listClass.publicItems[6]);  //throw exception
                      }
                      catch (Exception e)
                      {
                          Console.WriteLine(e.Message);
                      }
                  }
              }
          }

          Comment

          • Plater
            Recognized Expert Expert
            • Apr 2007
            • 7872

            #6
            From your original example (post#2), if you took the interface inheritance away from your class, did it work as it should? (Adding the item correctly)

            Also, does this code work for you:
            private ArrayList items = new ArrayList{0,1,2 ,3,4,5};
            I get compile errors about the format.


            EDIT: Using your sample code from the 2nd post, I changed the init line to this:
            IListInterface byRef = (IListInterface )new ListClass();
            And it worked correctly.

            Comment

            Working...