File: system\runtime\remoting\ichannel.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** File:    IChannel.cs
**
**
** Purpose: Defines the interfaces implemented by channels
**
**
===========================================================*/
namespace System.Runtime.Remoting.Channels {
    using System.Collections;
    using System.IO;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Metadata;
    using System.Security.Permissions;
    using System;
    using System.Globalization;
    
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IChannel
    {
        int ChannelPriority 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get; 
        }
        String ChannelName
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get; 
        }
        [System.Security.SecurityCritical]  // auto-generated_required
        String Parse(String url, out String objectURI);
    }
    
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IChannelSender : IChannel
    {
        [System.Security.SecurityCritical]  // auto-generated_required
        IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI);
    } // interface IChannelSender
    
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IChannelReceiver : IChannel
    {
        Object ChannelData 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
        [System.Security.SecurityCritical]  // auto-generated_required
        String[] GetUrlsForUri(String objectURI);
        [System.Security.SecurityCritical]  // auto-generated_required
        void StartListening(Object data);
        [System.Security.SecurityCritical]  // auto-generated_required
        void StopListening(Object data);
    } // interface IChannelReceiver 
 
 
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IChannelReceiverHook
    {
        String ChannelScheme
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
 
        bool WantsToListen
        { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
 
        IServerChannelSink ChannelSinkChain
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required
        void AddHookChannelUri(String channelUri);
        
    } // interface IChannelReceiverHook
 
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IClientChannelSinkProvider
    {
        [System.Security.SecurityCritical]  // auto-generated_required
        IClientChannelSink CreateSink(IChannelSender channel, String url, Object remoteChannelData);
 
        IClientChannelSinkProvider Next 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
            [System.Security.SecurityCritical]  // auto-generated_required
            set; 
        }
    } // interface IClientChannelSinkProvider
 
 
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IServerChannelSinkProvider
    {
        // The sink provider should also chain this call to the next provider in the chain.
        [System.Security.SecurityCritical]  // auto-generated_required
        void GetChannelData(IChannelDataStore channelData);
        
        [System.Security.SecurityCritical]  // auto-generated_required
        IServerChannelSink CreateSink(IChannelReceiver channel);
 
        IServerChannelSinkProvider Next
        { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
            [System.Security.SecurityCritical]  // auto-generated_required
            set;
        }
    } // interface IServerChannelSinkProvider
 
 
    // This has the same exact functionality as IClientChannelSinkProvider.
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IClientFormatterSinkProvider : IClientChannelSinkProvider
    {
    } // interface IClientFormatterSinkProvider
 
 
    // This has the same exact functionality as IServerChannelSinkProvider.
    // There may be multiple formatter sinks. If there are more than one, then one
    // formatter sink may decide to delegate the formatting responsibilities to the next
    // one.
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IServerFormatterSinkProvider : IServerChannelSinkProvider
    {
    } // interface IServerFormatterSinkProvider
 
 
 
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IClientChannelSink : IChannelSinkBase
    {
        // Parameters:
        //   msg - it's the "IMethodCallMessage"
        //   requestHeaders - headers to add to the outgoing message heading to server
        //   requestStream - stream headed towards the transport sink
        //   responseHeaders - headers that server returned
        //   responseStream - stream coming back from the transport sink
        [System.Security.SecurityCritical]  // auto-generated_required
        void ProcessMessage(IMessage msg,
                            ITransportHeaders requestHeaders, Stream requestStream,
                            out ITransportHeaders responseHeaders, out Stream responseStream);
                            
        // Parameters: (for async calls, the transport sink is responsible for doing the write
        //     and read asynchronously)
        //   sinkStack - channel sinks who called this one
        //   msg - it's the "IMessage" msg
        //   headers - headers to add to the outgoing message heading to server
        //   stream - stream headed towards the transport sink
        // Returns:
        //   IAsyncResult for this call.
        [System.Security.SecurityCritical]  // auto-generated_required
        void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg,
                                 ITransportHeaders headers, Stream stream);
                                 
        [System.Security.SecurityCritical]  // auto-generated_required
        void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, Object state,
                                  ITransportHeaders headers, Stream stream);
                                  
        // Parameters:
        //   msg - it's the "IMethodCallMessage"
        //   headers - headers to add to the outgoing message heading to server
        [System.Security.SecurityCritical]  // auto-generated_required
        Stream GetRequestStream(IMessage msg, ITransportHeaders headers);
 
 
        // the next channel sink in the chain
        IClientChannelSink NextChannelSink
        { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
    } // IClientChannelSink
    
 
 
    [Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
    public enum ServerProcessing
    {
        Complete, // server synchronously processed message
        OneWay,   // message dispatched and no response should be sent
        Async     // the call was dispatched asynchronously
                  //   (sink should store data on stack for later processing)
    } // ServerProcessing
 
 
    // Used for security sink and transport sinks.
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IServerChannelSink : IChannelSinkBase
    {
        // Parameters:
        //   sinkStack - channel sinks who called this one
        //   requestMsg - deserialized request message or null if the stream hasn't been deserialized
        //   requestHeaders - headers retrieved from the incoming message from client
        //   requestStream - stream to process and pass onto towards the deserialization sink.
        //   responseMsg - response message
        //   responseHeaders - headers to add to return message heading to client
        //   responseStream - stream heading back towards the transport sink
        // Returns:
        //   Provides information about how message was processed.
        [System.Security.SecurityCritical]  // auto-generated_required
        ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
                                        IMessage requestMsg,
                                        ITransportHeaders requestHeaders, Stream requestStream,
                                        out IMessage responseMsg, out ITransportHeaders responseHeaders,
                                        out Stream responseStream);
 
        // Parameters: (for async calls)
        //   sinkStack - sink stack (leading back to the server transport sink)
        //   headers - headers to add to return message heading to client
        //   stream - stream heading back towards the transport sink
        [System.Security.SecurityCritical]  // auto-generated_required
        void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state,
                                  IMessage msg, ITransportHeaders headers, Stream stream);                   
 
        // Parameters:
        //   sinkStack - sink stack (leading back to the server transport sink)  
        //   state - state that had been pushed to the stack by this sink
        //   msg - it's the "IMethodCallMessage"
        //   headers - headers to put in response message to client 
        [System.Security.SecurityCritical]  // auto-generated_required
        Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
                                 IMessage msg, ITransportHeaders headers);                               
 
 
        // the next channel sink in the chain
        IServerChannelSink NextChannelSink 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
 
    } // interface IServerChannelSink
 
 
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IChannelSinkBase
    {
        // This returns a dictionary through which properties on the sink may be retrieved
        // or configured. If a property is not present in this sink, it should delegate the
        // the property get or set to the next sink in the chain.
        IDictionary Properties 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
    }
 
 
 
    // Client formatter sinks are both a message sink and a channel sink.
    // They initially transform the message into a stream.
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IClientFormatterSink : IMessageSink, IClientChannelSink
    {
    } // interface IClientFormatterSink
 
 
 
 
    // Channels wishing to use the channel sink architecture must implement this interface
    //   on their ChannelData object.
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IChannelDataStore
    {
        String[] ChannelUris 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
        }
    
        Object this[Object key] 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
            [System.Security.SecurityCritical]  // auto-generated_required
            set;
        }
    } // interface IChannelDataStore
 
 
    // Used to store channel data for our remoting channels
    [System.Security.SecurityCritical]  // auto-generated_required
    [Serializable]
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class ChannelDataStore : IChannelDataStore
    {
        String[]           _channelURIs;  // list of channel uri's that map to this channel
        
        DictionaryEntry[]  _extraData;    // sink data
 
        // private constructor for shallow clone    
        private ChannelDataStore(String[] channelUrls, DictionaryEntry[] extraData)
        {
            _channelURIs = channelUrls;
            _extraData = extraData;
        }
 
        public ChannelDataStore(String[] channelURIs)
        {
            _channelURIs = channelURIs;
            _extraData = null;
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal ChannelDataStore InternalShallowCopy()
        {
            return new ChannelDataStore(_channelURIs, _extraData);
        }
 
 
        public String[] ChannelUris
        {
            [System.Security.SecurityCritical]
            get { return _channelURIs; }
            set { _channelURIs = value; }
        }
 
        // implementation of IChannelDataStore
        public Object this[Object key]
        {
            [System.Security.SecurityCritical]
            get 
            {
                // look for matching key in extra data list
                foreach (DictionaryEntry entry in _extraData)
                {
                    if (entry.Key.Equals(key))
                        return entry.Value;                    
                }
 
                // entry not found
                return null;
            } // get
 
            [System.Security.SecurityCritical]
            set
            {
                if (_extraData == null)
                {
                    _extraData = new DictionaryEntry[1];
                    _extraData[0] = new DictionaryEntry(key, value);
                }
                else
                {
                    int length =_extraData.Length;
                    DictionaryEntry[] newList = new DictionaryEntry[length + 1];
                    int co = 0;
                    for (; co < length; co++)
                        newList[co] = _extraData[co];
                    newList[co] = new DictionaryEntry(key, value); // set last value
                    _extraData = newList;
                }
            } // set
        } // Object this[Object key]
        
    } // class ChannelDataStore
 
 
 
 
[System.Runtime.InteropServices.ComVisible(true)]
    public interface ITransportHeaders
    {
        // Should add headers in order, and remove them if somebody tries to set
        //   it to null.
        Object this[Object key]
        { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get;
            [System.Security.SecurityCritical]  // auto-generated_required
            set;
        }
 
        // This is required to handback an enumerator which iterates over all entries
        //   in the headers.
        [System.Security.SecurityCritical]  // auto-generated_required
        IEnumerator GetEnumerator();
    } // interface ITransportHeaders
 
 
    // TransportHeaders is used to store a collection of headers that is used in the channel sinks.
    // The header list preserves order, and keeps headers in the order that they were originally
    // added. You can use the foreach statement to iterate over the contents of the header list 
    // which contains objects of type DictionaryEntry. Keys are required to be strings, and
    // comparisons are done on a case-insensitive basis.
    [System.Security.SecurityCritical]  // auto-generated_required
    [Serializable]
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]         
    [System.Runtime.InteropServices.ComVisible(true)]
    public class TransportHeaders : ITransportHeaders
    {
        private ArrayList _headerList; // array of type DictionaryEntry
    
        public TransportHeaders()
        {
            // The default capacity is larger than we'll typically need so start off at 6.
            _headerList = new ArrayList(6);
        } // TransportHeaders
 
 
        // dictionary like interface
        public Object this[Object key]
        {
            [System.Security.SecurityCritical]
            get 
            {
                String strKey = (String)key;
                
                // look for matching key in header list
                foreach (DictionaryEntry entry in _headerList)
                {
                    if (String.Compare((String)entry.Key, strKey, StringComparison.OrdinalIgnoreCase) == 0)
                        return entry.Value;                    
                }
 
                // entry not found
                return null;
            } // get
 
            [System.Security.SecurityCritical]
            set
            {
                if (key == null)
                    return;
 
                String strKey = (String)key;
 
                // remove this entry if it's already in the list
                int co = _headerList.Count - 1;
                while (co >= 0)
                {                
                    String headerKey = (String)((DictionaryEntry)_headerList[co]).Key;
                    if (String.Compare(headerKey, strKey, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        _headerList.RemoveAt(co);
                        break;
                    }
                    co--;
                }
 
                // otherwise, add this entry
                if (value != null)
                {
                    _headerList.Add(new DictionaryEntry(key, value));
                }
            } // set
        } // Object this[Object key]
        
        [System.Security.SecurityCritical]
        public IEnumerator GetEnumerator() 
        {
            return _headerList.GetEnumerator(); 
        } // GetEnumerator
        
    } // TransportHeaders
 
 
 
    // All sink providers must have a constructor that accepts a hashtable and 
    //   an ArrayList of these structures if they want to be used from a config file.
[System.Runtime.InteropServices.ComVisible(true)]
    public class SinkProviderData
    {
        private String _name;
        private Hashtable _properties = new Hashtable(StringComparer.InvariantCultureIgnoreCase);
        private ArrayList _children = new ArrayList();
 
        public SinkProviderData(String name) 
        {
            _name = name;
        }
 
        public String Name { get { return _name; } }
        public IDictionary Properties { get { return _properties; } }
        public IList Children { get { return _children; } }
    } // class SinkProviderData
 
 
 
 
 
    // Base implementation for channel sinks that want to supply properties.
    // The derived class only needs to implement the Keys property and this[].
    [System.Security.SecurityCritical]  // auto-generated_required
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class BaseChannelSinkWithProperties : BaseChannelObjectWithProperties
    {       
        protected BaseChannelSinkWithProperties() : base()
        {
        }    
    } // class BaseChannelSinkWithProperties
 
 
    // This provides a base implementation of a channel that wants
    // to provide a dictionary interface. It handles the complexity
    // of asking a channel sink chain for their properties.
    // Once the channel constructs its sink chain (usually only applicable
    // for server channels) it should set the SinksWithProperties property.
    // The properties only get chained for channel sinks when the users asks
    // for the "Properties" dictionary. If you just go through the dictionary interface
    // you'll only get the channel specific properties.
    // The derived class only needs to implement the Keys property and this[].
    [System.Security.SecurityCritical]  // auto-generated_required
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class BaseChannelWithProperties : BaseChannelObjectWithProperties
    {    
        protected IChannelSinkBase SinksWithProperties = null;
 
        protected BaseChannelWithProperties() : base()
        {
        }
 
        // This is overridden so that server channels can expose the properties
        //   of their channel sinks through a flat dictionary interface.
        public override IDictionary Properties 
        {
            [System.Security.SecurityCritical]  // auto-generated_required
            get
            {
                // collect dictionaries for all channel sinks and return
                //   aggregate dictionary
                ArrayList dictionaries = new ArrayList();
 
                // add the channel itself
                dictionaries.Add(this);
 
                if (SinksWithProperties != null)
                {
                    IServerChannelSink srvSink = SinksWithProperties as IServerChannelSink;
                    if (srvSink != null)
                    {
                        while (srvSink != null)
                        {
                            IDictionary dict = srvSink.Properties;
                            if (dict != null)
                                dictionaries.Add(dict);
 
                            srvSink = srvSink.NextChannelSink;
                        }
                    }
                    else
                    {
                        // we know it's a client channel sink
                        IClientChannelSink chnlSink = (IClientChannelSink)SinksWithProperties;                        
                        
                        while (chnlSink != null)
                        {
                            IDictionary dict = chnlSink.Properties;
                            if (dict != null)
                                dictionaries.Add(dict);
 
                            chnlSink = chnlSink.NextChannelSink;
                        }
                    }                    
                }
 
                // return a dictionary that spans all dictionaries provided
                return new AggregateDictionary(dictionaries);
            }
        } 
 
    } // class BaseChannelWithProperties
 
    
 
 
 
 
 
    // Base implementation for channel sinks that want to supply properties.
    // The derived class only needs to implement the Keys property and this[].
    [System.Security.SecurityCritical]  // auto-generated_required
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class BaseChannelObjectWithProperties : IDictionary
    {
        protected BaseChannelObjectWithProperties()
        {
        }   
 
        public virtual IDictionary Properties { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get { return this; } 
        }
 
        // 
        // IDictionary implementation        
        //
 
        public virtual Object this[Object key]
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get { return null; }
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            set { throw new NotImplementedException(); } 
        } // Object this[Object key]
 
        public virtual ICollection Keys
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get { return null; }
        }
        
        public virtual ICollection Values
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get
            {
                ICollection keys = Keys;
                if (keys == null)
                    return null;
 
                ArrayList values = new ArrayList();
                foreach (Object key in keys)
                {
                    values.Add(this[key]);
                }                
 
                return values;
            }
        }       
 
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public virtual bool Contains(Object key) 
        {
            if (key == null)
                return false;
 
            ICollection keySet = Keys;
            if (keySet == null)
                return false;
 
            String keyStr = key as String;
        
            foreach (Object someKey in keySet)
            {
                if (keyStr != null)
                {
                    String someKeyStr = someKey as String;
                    if (someKeyStr != null)
                    {
                        // compare the key strings case-insensitively
                        if (String.Compare(keyStr, someKeyStr, StringComparison.OrdinalIgnoreCase) == 0)
                            return true;
 
                        continue;
                    }
                }                
            
                if (key.Equals(someKey))
                    return true;
            }
 
            return false;
        } // Contains
 
        public virtual bool IsReadOnly
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get { return false; }
        }
        public virtual bool IsFixedSize
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get { return true; }
        } 
 
        // The following three methods should never be implemented because
        // they don't apply to the way IDictionary is being used in this case
        // (plus, IsFixedSize returns true.)
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public virtual void Add(Object key, Object value) { throw new NotSupportedException(); }
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public virtual void Clear() { throw new NotSupportedException(); }
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public virtual void Remove(Object key) { throw new NotSupportedException(); }
 
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public virtual IDictionaryEnumerator GetEnumerator()
        {
            return new DictionaryEnumeratorByKeys(this);
        } // GetEnumerator
                            
 
        //
        // end of IDictionary implementation 
        //
 
        //
        // ICollection implementation 
        //
 
         //ICollection
 
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public virtual void CopyTo(Array array, int index) { throw new NotSupportedException(); }
 
        public virtual int Count
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get 
            {
                ICollection keySet = Keys;
                if (keySet == null)
                    return 0;
                    
                return keySet.Count; 
            }
        } // Count
 
        public virtual Object SyncRoot
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get { return this; }
        }
        public virtual bool IsSynchronized
        {
            [System.Security.SecuritySafeCritical] // overrides public transparent member
            get { return false; }
        }
 
        //
        // end of ICollection implementation
        //
 
        //IEnumerable
        /// <internalonly/>
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new DictionaryEnumeratorByKeys(this);
        }
    
    } // class BaseChannelObjectWithProperties
 
 
 
    // an enumerator based off of a key set
    internal class DictionaryEnumeratorByKeys : IDictionaryEnumerator
    {
        IDictionary _properties;
        IEnumerator _keyEnum;
    
        public DictionaryEnumeratorByKeys(IDictionary properties)
        {
            _properties = properties;
            _keyEnum = properties.Keys.GetEnumerator();
        } // PropertyEnumeratorByKeys
 
        public bool MoveNext() { return _keyEnum.MoveNext(); }        
        public void Reset() { _keyEnum.Reset(); }        
        public Object Current { get { return Entry; } }
 
        public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
        
        public Object Key { get { return _keyEnum.Current; } }
        public Object Value { get { return _properties[Key]; } }       
        
    } // DictionaryEnumeratorByKeys
 
 
    // combines multiple dictionaries into one
    //   (used for channel sink properties
    internal class AggregateDictionary : IDictionary
    {
        private ICollection _dictionaries;
            
        public AggregateDictionary(ICollection dictionaries)
        { 
            _dictionaries = dictionaries;
        } // AggregateDictionary  
 
        // 
        // IDictionary implementation        
        //
 
        public virtual Object this[Object key]
        {
            get 
            {
                foreach (IDictionary dict in _dictionaries)
                {
                    if (dict.Contains(key))
                        return dict[key];
                }
            
                return null; 
            }
                
            set
            {
                foreach (IDictionary dict in _dictionaries)
                {
                    if (dict.Contains(key))
                        dict[key] = value;
                }
            } 
        } // Object this[Object key]
 
        public virtual ICollection Keys 
        {
            get
            {
                ArrayList keys = new ArrayList();
                // add keys from every dictionary
                foreach (IDictionary dict in _dictionaries)
                {
                    ICollection dictKeys = dict.Keys;
                    if (dictKeys != null)
                    {
                        foreach (Object key in dictKeys)
                        {
                            keys.Add(key);
                        }
                    }
                }
 
                return keys;
            }
        } // Keys
        
        public virtual ICollection Values
        {
            get
            {
                ArrayList values = new ArrayList();
                // add values from every dictionary
                foreach (IDictionary dict in _dictionaries)
                {
                    ICollection dictValues = dict.Values;
                    if (dictValues != null)
                    {
                        foreach (Object value in dictValues)
                        {
                            values.Add(value);
                        }
                    }
                }
 
                return values;
            }
        } // Values
 
        public virtual bool Contains(Object key) 
        {
            foreach (IDictionary dict in _dictionaries)
            {
                if (dict.Contains(key))
                    return true;
            }
            
            return false; 
        } // Contains
 
        public virtual bool IsReadOnly { get { return false; } }
        public virtual bool IsFixedSize { get { return true; } } 
 
        // The following three methods should never be implemented because
        // they don't apply to the way IDictionary is being used in this case
        // (plus, IsFixedSize returns true.)
        public virtual void Add(Object key, Object value) { throw new NotSupportedException(); }
        public virtual void Clear() { throw new NotSupportedException(); }
        public virtual void Remove(Object key) { throw new NotSupportedException(); }
        
        public virtual IDictionaryEnumerator GetEnumerator()
        {
            return new DictionaryEnumeratorByKeys(this);
        } // GetEnumerator
                            
 
        //
        // end of IDictionary implementation 
        //
 
        //
        // ICollection implementation 
        //
 
        //ICollection
 
        public virtual void CopyTo(Array array, int index) { throw new NotSupportedException(); }
 
        public virtual int Count 
        {
            get 
            {
                int count = 0;
            
                foreach (IDictionary dict in _dictionaries)
                {
                    count += dict.Count;
                }
 
                return count;
            }
        } // Count
        
        public virtual Object SyncRoot { get { return this; } }
        public virtual bool IsSynchronized { get { return false; } }
 
        //
        // end of ICollection implementation
        //
 
        //IEnumerable
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new DictionaryEnumeratorByKeys(this);
        }
    
    } // class AggregateDictionary
 
 
    
} // namespace System.Runtime.Remoting