The Labs \ Source Viewer \ SSCLI \ System.CodeDom \ CodeTypeReference

  1. //------------------------------------------------------------------------------
  2. // <copyright file="CodeTypeReference.cs" company="Microsoft">
  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. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.CodeDom
  16. {
  17.    
  18.     using System.Diagnostics;
  19.     using System;
  20.     using Microsoft.Win32;
  21.     using System.Collections;
  22.     using System.Runtime.InteropServices;
  23.     using System.Runtime.Serialization;
  24.     using System.Globalization;
  25.    
  26.     [ComVisible(true), Serializable(), FlagsAttribute()]
  27.     public enum CodeTypeReferenceOptions
  28.     {
  29.         GlobalReference = 1,
  30.         GenericTypeParameter = 2
  31.     }
  32.    
  33.     /// <devdoc>
  34.     /// <para>
  35.     /// Represents a Type
  36.     /// </para>
  37.     /// </devdoc>
  38.     [ClassInterface(ClassInterfaceType.AutoDispatch), ComVisible(true), Serializable()]
  39.     public class CodeTypeReference : CodeObject
  40.     {
  41.         private string baseType;
  42.         [OptionalField()]
  43.         private bool isInterface;
  44.         private int arrayRank;
  45.         private CodeTypeReference arrayElementType;
  46.         [OptionalField()]
  47.         private CodeTypeReferenceCollection typeArguments;
  48.         [OptionalField()]
  49.         private CodeTypeReferenceOptions referenceOptions;
  50.         [OptionalField()]
  51.         private bool needsFixup = false;
  52.        
  53.         public CodeTypeReference()
  54.         {
  55.             baseType = string.Empty;
  56.             this.arrayRank = 0;
  57.             this.arrayElementType = null;
  58.         }
  59.        
  60.         public CodeTypeReference(Type type)
  61.         {
  62.             if (type == null)
  63.                 throw new ArgumentNullException("type");
  64.            
  65.             if (type.IsArray) {
  66.                 this.arrayRank = type.GetArrayRank();
  67.                 this.arrayElementType = new CodeTypeReference(type.GetElementType());
  68.                 this.baseType = null;
  69.             }
  70.             else {
  71.                 Initialize(type.FullName);
  72.                 this.arrayRank = 0;
  73.                 this.arrayElementType = null;
  74.             }
  75.            
  76.             this.isInterface = type.IsInterface;
  77.         }
  78.        
  79.         public CodeTypeReference(Type type, CodeTypeReferenceOptions codeTypeReferenceOption) : this(type)
  80.         {
  81.             referenceOptions = codeTypeReferenceOption;
  82.         }
  83.        
  84.         public CodeTypeReference(string typeName, CodeTypeReferenceOptions codeTypeReferenceOption) : this(typeName)
  85.         {
  86.             referenceOptions = codeTypeReferenceOption;
  87.         }
  88.        
  89.         /// <devdoc>
  90.         /// <para>[To be supplied.]</para>
  91.         /// </devdoc>
  92.        
  93.         // We support the reflection format for generice type name.
  94.         // The format is like:
  95.         //
  96.         public CodeTypeReference(string typeName)
  97.         {
  98.             Initialize(typeName);
  99.         }
  100.        
  101.         private void Initialize(string typeName)
  102.         {
  103.             if (typeName == null || typeName.Length == 0) {
  104.                 typeName = typeof(void).FullName;
  105.                 this.baseType = typeName;
  106.                 this.arrayRank = 0;
  107.                 this.arrayElementType = null;
  108.                 return;
  109.             }
  110.            
  111.             typeName = RipOffAssemblyInformationFromTypeName(typeName);
  112.            
  113.             int end = typeName.Length - 1;
  114.             int current = end;
  115.             needsFixup = true;
  116.             // default to true, and if we find arity or generic type args, we'll clear the flag.
  117.             // Scan the entire string for valid array tails and store ranks for array tails
  118.             // we found in a queue.
  119.             Queue q = new Queue();
  120.             while (current >= 0) {
  121.                 int rank = 1;
  122.                 if (typeName[current--] == ']') {
  123.                     while (current >= 0 && typeName[current] == ',') {
  124.                         rank++;
  125.                         current--;
  126.                     }
  127.                    
  128.                     if (current >= 0 && typeName[current] == '[') {
  129.                         // found a valid array tail
  130.                         q.Enqueue(rank);
  131.                         current--;
  132.                         end = current;
  133.                         continue;
  134.                     }
  135.                 }
  136.                 break;
  137.             }
  138.            
  139.             // Try find generic type arguments
  140.             current = end;
  141.             ArrayList typeArgumentList = new ArrayList();
  142.             Stack subTypeNames = new Stack();
  143.             if (current > 0 && typeName[current--] == ']') {
  144.                 needsFixup = false;
  145.                 int unmatchedRightBrackets = 1;
  146.                 int subTypeNameEndIndex = end;
  147.                
  148.                 // Try find the matching '[', if we can't find it, we will not try to parse the string
  149.                 while (current >= 0) {
  150.                     if (typeName[current] == '[') {
  151.                         // break if we found matched brackets
  152.                         if (--unmatchedRightBrackets == 0)
  153.                             break;
  154.                     }
  155.                     else if (typeName[current] == ']') {
  156.                         ++unmatchedRightBrackets;
  157.                     }
  158.                     else if (typeName[current] == ',' && unmatchedRightBrackets == 1) {
  159.                         //
  160.                         if (current + 1 < subTypeNameEndIndex) {
  161.                             subTypeNames.Push(typeName.Substring(current + 1, subTypeNameEndIndex - current - 1));
  162.                         }
  163.                        
  164.                         subTypeNameEndIndex = current;
  165.                        
  166.                     }
  167.                     --current;
  168.                 }
  169.                
  170.                 if (current > 0 && (end - current - 1) > 0) {
  171.                     // push the last generic type argument name if there is any
  172.                     if (current + 1 < subTypeNameEndIndex) {
  173.                         subTypeNames.Push(typeName.Substring(current + 1, subTypeNameEndIndex - current - 1));
  174.                     }
  175.                    
  176.                     // we found matched brackets and the brackets contains some characters.
  177.                     while (subTypeNames.Count > 0) {
  178.                         string name = RipOffAssemblyInformationFromTypeName((string)subTypeNames.Pop());
  179.                         typeArgumentList.Add(new CodeTypeReference(name));
  180.                     }
  181.                     end = current - 1;
  182.                 }
  183.             }
  184.            
  185.             if (end < 0) {
  186.                 // this can happen if we have some string like "[...]"
  187.                 this.baseType = typeName;
  188.                 return;
  189.             }
  190.            
  191.             if (q.Count > 0) {
  192.                
  193.                 CodeTypeReference type = new CodeTypeReference(typeName.Substring(0, end + 1));
  194.                
  195.                 for (int i = 0; i < typeArgumentList.Count; i++) {
  196.                     type.TypeArguments.Add((CodeTypeReference)typeArgumentList[i]);
  197.                 }
  198.                
  199.                 while (q.Count > 1) {
  200.                     type = new CodeTypeReference(type, (int)q.Dequeue());
  201.                 }
  202.                
  203.                 // we don't need to create a new CodeTypeReference for the last one.
  204.                 Debug.Assert(q.Count == 1, "We should have one and only one in the rank queue.");
  205.                 this.baseType = null;
  206.                 this.arrayRank = (int)q.Dequeue();
  207.                 this.arrayElementType = type;
  208.             }
  209.             else if (typeArgumentList.Count > 0) {
  210.                 for (int i = 0; i < typeArgumentList.Count; i++) {
  211.                     TypeArguments.Add((CodeTypeReference)typeArgumentList[i]);
  212.                 }
  213.                
  214.                 this.baseType = typeName.Substring(0, end + 1);
  215.             }
  216.             else {
  217.                 this.baseType = typeName;
  218.             }
  219.            
  220.             // Now see if we have some arity. baseType could be null if this is an array type.
  221.             if (baseType != null && baseType.IndexOf('`') != -1)
  222.                 needsFixup = false;
  223.            
  224.         }
  225.        
  226.         public CodeTypeReference(string typeName, params CodeTypeReference[] typeArguments) : this(typeName)
  227.         {
  228.             if (typeArguments != null && typeArguments.Length > 0) {
  229.                 TypeArguments.AddRange(typeArguments);
  230.             }
  231.         }
  232.        
  233.         public CodeTypeReference(CodeTypeParameter typeParameter) : this((typeParameter == null) ? (string)null : typeParameter.Name)
  234.         {
  235.             referenceOptions = CodeTypeReferenceOptions.GenericTypeParameter;
  236.         }
  237.        
  238.         /// <devdoc>
  239.         /// <para>[To be supplied.]</para>
  240.         /// </devdoc>
  241.         public CodeTypeReference(string baseType, int rank)
  242.         {
  243.             this.baseType = null;
  244.             this.arrayRank = rank;
  245.             this.arrayElementType = new CodeTypeReference(baseType);
  246.         }
  247.        
  248.         /// <devdoc>
  249.         /// <para>[To be supplied.]</para>
  250.         /// </devdoc>
  251.         public CodeTypeReference(CodeTypeReference arrayType, int rank)
  252.         {
  253.             this.baseType = null;
  254.             this.arrayRank = rank;
  255.             this.arrayElementType = arrayType;
  256.         }
  257.        
  258.         /// <devdoc>
  259.         /// <para>[To be supplied.]</para>
  260.         /// </devdoc>
  261.         public CodeTypeReference ArrayElementType {
  262.             get { return arrayElementType; }
  263.             set { arrayElementType = value; }
  264.         }
  265.        
  266.         /// <devdoc>
  267.         /// <para>[To be supplied.]</para>
  268.         /// </devdoc>
  269.         public int ArrayRank {
  270.             get { return arrayRank; }
  271.             set { arrayRank = value; }
  272.         }
  273.        
  274.         /// <devdoc>
  275.         /// <para>[To be supplied.]</para>
  276.         /// </devdoc>
  277.         public string BaseType {
  278.             get {
  279.                 if (arrayRank > 0 && arrayElementType != null) {
  280.                     return arrayElementType.BaseType;
  281.                 }
  282.                 if (String.IsNullOrEmpty(baseType))
  283.                     return string.Empty;
  284.                
  285.                 string returnType = baseType;
  286.                 if (needsFixup && TypeArguments.Count > 0)
  287.                     returnType = returnType + '`' + TypeArguments.Count.ToString(CultureInfo.InvariantCulture);
  288.                
  289.                 return returnType;
  290.                
  291.             }
  292.             set {
  293.                 baseType = value;
  294.                 Initialize(baseType);
  295.             }
  296.         }
  297.        
  298.         [System.Runtime.InteropServices.ComVisible(false)]
  299.         public CodeTypeReferenceOptions Options {
  300.             get { return referenceOptions; }
  301.             set { referenceOptions = value; }
  302.         }
  303.        
  304.         [System.Runtime.InteropServices.ComVisible(false)]
  305.         public CodeTypeReferenceCollection TypeArguments {
  306.             get {
  307.                 if (arrayRank > 0 && arrayElementType != null) {
  308.                     return arrayElementType.TypeArguments;
  309.                 }
  310.                
  311.                 if (typeArguments == null) {
  312.                     typeArguments = new CodeTypeReferenceCollection();
  313.                 }
  314.                 return typeArguments;
  315.             }
  316.         }
  317.        
  318.         internal bool IsInterface {
  319. // Note that this only works correctly if the Type ctor was used. Otherwise, it's always false.
  320.             get { return this.isInterface; }
  321.         }
  322.        
  323.         //
  324.         // The string for generic type argument might contain assembly information and square bracket pair.
  325.         // There might be leading spaces in front the type name.
  326.         // Following function will rip off assembly information and brackets
  327.         // Following is an example:
  328.         // " [System.Collections.Generic.List[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral,
  329.         // PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]"
  330.         //
  331.         private string RipOffAssemblyInformationFromTypeName(string typeName)
  332.         {
  333.             int start = 0;
  334.             int end = typeName.Length - 1;
  335.             string result = typeName;
  336.            
  337.             // skip white space in the beginning
  338.             while (start < typeName.Length && Char.IsWhiteSpace(typeName[start]))
  339.                 start++;
  340.             while (end >= 0 && Char.IsWhiteSpace(typeName[end]))
  341.                 end--;
  342.            
  343.             if (start < end) {
  344.                 if (typeName[start] == '[' && typeName[end] == ']') {
  345.                     start++;
  346.                     end--;
  347.                 }
  348.                
  349.                 // if we still have a ] at the end, there's no assembly info.
  350.                 if (typeName[end] != ']') {
  351.                     int commaCount = 0;
  352.                     for (int index = end; index >= start; index--) {
  353.                         if (typeName[index] == ',') {
  354.                             commaCount++;
  355.                             if (commaCount == 4) {
  356.                                 result = typeName.Substring(start, index - start);
  357.                                 break;
  358.                             }
  359.                         }
  360.                     }
  361.                 }
  362.             }
  363.            
  364.             return result;
  365.         }
  366.     }
  367. }

Developer Fusion