The Labs \ Source Viewer \ SSCLI \ System.Runtime.Serialization \ SurrogateHashtable

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: SurrogateSelector
  18. **
  19. **
  20. ** Purpose: A user-supplied class for doing the type to surrogate
  21. **          mapping.
  22. **
  23. **
  24. ===========================================================*/
  25. namespace System.Runtime.Serialization
  26. {
  27.    
  28.     using System.Runtime.Remoting;
  29.     using System;
  30.     using System.Collections;
  31.     using System.Security.Permissions;
  32.     [System.Runtime.InteropServices.ComVisible(true)]
  33.     public class SurrogateSelector : ISurrogateSelector
  34.     {
  35.        
  36.         internal SurrogateHashtable m_surrogates;
  37.         internal ISurrogateSelector m_nextSelector;
  38.        
  39.         public SurrogateSelector()
  40.         {
  41.             m_surrogates = new SurrogateHashtable(32);
  42.         }
  43.        
  44.         // Adds a surrogate to the list of surrogates checked.
  45.         public virtual void AddSurrogate(Type type, StreamingContext context, ISerializationSurrogate surrogate)
  46.         {
  47.             if (type == null) {
  48.                 throw new ArgumentNullException("type");
  49.             }
  50.             if (surrogate == null) {
  51.                 throw new ArgumentNullException("surrogate");
  52.             }
  53.            
  54.             SurrogateKey key = new SurrogateKey(type, context);
  55.             m_surrogates.Add(key, surrogate);
  56.             // Hashtable does duplicate checking.
  57.         }
  58.        
  59.         private static bool HasCycle(ISurrogateSelector selector)
  60.         {
  61.             ISurrogateSelector head;
  62.             ISurrogateSelector tail;
  63.            
  64.             BCLDebug.Assert(selector != null, "[HasCycle]selector!=null");
  65.            
  66.            
  67.             head = selector;
  68.             tail = selector;
  69.            
  70.             while (head != null) {
  71.                 head = head.GetNextSelector();
  72.                 if (head == null) {
  73.                     return true;
  74.                 }
  75.                 if (head == tail) {
  76.                     return false;
  77.                 }
  78.                 head = head.GetNextSelector();
  79.                 tail = tail.GetNextSelector();
  80.                
  81.                 if (head == tail) {
  82.                     return false;
  83.                 }
  84.             }
  85.            
  86.             return true;
  87.            
  88.         }
  89.        
  90.         // Adds another selector to check if we don't have match within this selector.
  91.         // The logic is:"Add this onto the list as the first thing that you check after yourself."
  92.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  93.         public virtual void ChainSelector(ISurrogateSelector selector)
  94.         {
  95.             ISurrogateSelector temp;
  96.             ISurrogateSelector tempCurr;
  97.             ISurrogateSelector tempPrev;
  98.             ISurrogateSelector tempEnd;
  99.            
  100.             if (selector == null) {
  101.                 throw new ArgumentNullException("selector");
  102.             }
  103.            
  104.             //
  105.             // Verify that we don't try and add ourself twice.
  106.             //
  107.             if (selector == this) {
  108.                 throw new SerializationException(Environment.GetResourceString("Serialization_DuplicateSelector"));
  109.             }
  110.            
  111.             //
  112.             // Verify that the argument doesn't contain a cycle.
  113.             //
  114.             if (!HasCycle(selector)) {
  115.                 throw new ArgumentException(Environment.GetResourceString("Serialization_SurrogateCycleInArgument"), "selector");
  116.             }
  117.            
  118.             //
  119.             // Check for a cycle that would lead back to this. We find the end of the list that we're being asked to
  120.             // insert for use later.
  121.             //
  122.             tempCurr = selector.GetNextSelector();
  123.             tempEnd = selector;
  124.             while (tempCurr != null && tempCurr != this) {
  125.                 tempEnd = tempCurr;
  126.                 tempCurr = tempCurr.GetNextSelector();
  127.             }
  128.             if (tempCurr == this) {
  129.                 throw new ArgumentException(Environment.GetResourceString("Serialization_SurrogateCycle"), "selector");
  130.             }
  131.            
  132.             //
  133.             // Check for a cycle later in the list which would be introduced by this insertion.
  134.             //
  135.             tempCurr = selector;
  136.             tempPrev = selector;
  137.             while (tempCurr != null) {
  138.                 if (tempCurr == tempEnd) {
  139.                     tempCurr = this.GetNextSelector();
  140.                 }
  141.                 else {
  142.                     tempCurr = tempCurr.GetNextSelector();
  143.                 }
  144.                 if (tempCurr == null) {
  145.                     break;
  146.                 }
  147.                 if (tempCurr == tempPrev) {
  148.                     throw new ArgumentException(Environment.GetResourceString("Serialization_SurrogateCycle"), "selector");
  149.                 }
  150.                
  151.                 if (tempCurr == tempEnd) {
  152.                     tempCurr = this.GetNextSelector();
  153.                 }
  154.                 else {
  155.                     tempCurr = tempCurr.GetNextSelector();
  156.                 }
  157.                
  158.                
  159.                 if (tempPrev == tempEnd) {
  160.                     tempPrev = this.GetNextSelector();
  161.                 }
  162.                 else {
  163.                     tempPrev = tempPrev.GetNextSelector();
  164.                 }
  165.                 if (tempCurr == tempPrev) {
  166.                     throw new ArgumentException(Environment.GetResourceString("Serialization_SurrogateCycle"), "selector");
  167.                 }
  168.             }
  169.            
  170.             //
  171.             // Add the new selector and it's entire chain of selectors as the next thing that
  172.             // we check.
  173.             //
  174.             temp = m_nextSelector;
  175.             m_nextSelector = selector;
  176.             if (temp != null) {
  177.                 tempEnd.ChainSelector(temp);
  178.             }
  179.         }
  180.        
  181.         // Get the next selector on the chain of selectors.
  182.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  183.         public virtual ISurrogateSelector GetNextSelector()
  184.         {
  185.             return m_nextSelector;
  186.         }
  187.        
  188.         // Gets the surrogate for a particular type. If this selector can't
  189.         // provide a surrogate, it checks with all of it's children before returning null.
  190.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  191.         public virtual ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
  192.         {
  193.             if (type == null) {
  194.                 throw new ArgumentNullException("type");
  195.             }
  196.            
  197.             selector = this;
  198.            
  199.             SurrogateKey key = new SurrogateKey(type, context);
  200.             ISerializationSurrogate temp = (ISerializationSurrogate)m_surrogates[key];
  201.             if (temp != null) {
  202.                 return temp;
  203.             }
  204.             if (m_nextSelector != null) {
  205.                 return m_nextSelector.GetSurrogate(type, context, out selector);
  206.             }
  207.             return null;
  208.         }
  209.        
  210.         // Removes the surrogate associated with a given type. Does not
  211.         // check chained surrogates.
  212.         public virtual void RemoveSurrogate(Type type, StreamingContext context)
  213.         {
  214.             if (type == null) {
  215.                 throw new ArgumentNullException("type");
  216.             }
  217.            
  218.            
  219.             SurrogateKey key = new SurrogateKey(type, context);
  220.             m_surrogates.Remove(key);
  221.         }
  222.     }
  223.    
  224.     [Serializable()]
  225.     internal class SurrogateKey
  226.     {
  227.         internal Type m_type;
  228.         internal StreamingContext m_context;
  229.        
  230.         internal SurrogateKey(Type type, StreamingContext context)
  231.         {
  232.             m_type = type;
  233.             m_context = context;
  234.         }
  235.        
  236.         public override int GetHashCode()
  237.         {
  238.             return m_type.GetHashCode();
  239.         }
  240.     }
  241.    
  242.     // Subclass to override KeyEquals.
  243.     class SurrogateHashtable : Hashtable
  244.     {
  245.         internal SurrogateHashtable(int size) : base(size)
  246.         {
  247.             ;
  248.         }
  249.         // Must return true if the context to serialize for (givenContext)
  250.         // is a subset of the context for which the serialization selector is provided (presentContext)
  251.         // Note: This is done by overriding KeyEquals rather than overriding Equals() in the SurrogateKey
  252.         // class because Equals() method must be commutative.
  253.         protected override bool KeyEquals(object key, object item)
  254.         {
  255.             SurrogateKey givenValue = (SurrogateKey)item;
  256.             SurrogateKey presentValue = (SurrogateKey)key;
  257.             return presentValue.m_type == givenValue.m_type && (presentValue.m_context.m_state & givenValue.m_context.m_state) == givenValue.m_context.m_state && presentValue.m_context.Context == givenValue.m_context.Context;
  258.         }
  259.     }
  260.    
  261. }

Developer Fusion