TypeInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / AddIn / AddIn / System / Addin / MiniReflection / TypeInfo.cs / 1305376 / TypeInfo.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  TypeInfo 
**
** Purpose: Abstracts out the notion of a type, so we can 
**     support generic type parameters & possible "pipeline
**     constraints" based on the types present in the pipeline.
**
===========================================================*/ 
using System;
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Globalization; 
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text; 
using System.AddIn.MiniReflection.MetadataReader;
using System.AddIn.Hosting; 
using System.Diagnostics.Contracts; 

namespace System.AddIn.MiniReflection 
{
    // While this is currently just a wrapper for a String (the
    // assembly-qualified type name), eventually we should store more info
    // here, such as what the generic type parameters are to a class, 
    // and perhaps constraint-like info.  Say we have an add-in adapter
    // w/ a constructor taking an add-in base called AB.  The add-in base 
    // of course is AB.  We can only connect from the add-in adapter 
    // all the way through the add-in if the add-in subclasses AB.
    // The hope is this class will provide the right level of abstraction to 
    // support generic add-in parts in the future.
    [Serializable]
    internal sealed class TypeInfo : IEquatable, ISerializable
    { 
        [Flags]
        internal enum Representation { 
            None = 0, 
            Token = 1,
            Name = 2, 
            AssemblyQualifiedName = 4,
            ReflectionType = 8,
            TypeRef = 0x10,
        } 

        private static ICollection Warnings; 
        private const String AssemblyFieldName = "_assembly"; 
        private const String ModuleFieldName = "_module";
        private const String MDTokenFieldName = "_mdToken"; 
        private const String TypeNameFieldName = "_typeName";
        private const String NameSpaceFieldName = "_nameSpace";
        private const String AssemblyQualifiedFieldName = "_assemblyQualifiedName";
        private const String RepresentationFieldName = "_representation"; 
        private const String IsGenericFieldName = "_isGeneric";
 
        private MiniAssembly _assembly; // note that for TypeInfos coming from TypeRefs, this is the referencing assembly 
        private MiniModule _module;
        private MetadataToken _mdToken; 
        private String _typeName;
        private String _nameSpace;
        private String _assemblyQualifiedName;
        private static UTF8Encoding s_encoder = new UTF8Encoding(false, true); 

        [NonSerialized] 
        private Type _reflectionType;  // Don't load Type objects in the wrong AD! 
        private Representation _representation;
 
        private bool _isGeneric;

        internal TypeInfo(MetadataToken typeDef, MiniAssembly assembly)
        { 
            System.Diagnostics.Contracts.Contract.Requires(assembly != null);
            System.Diagnostics.Contracts.Contract.Requires(typeDef.Table == MDTables.Tables.TypeDef); 
 
            _mdToken = typeDef;
            _assembly = assembly; 
            _representation = Representation.Token;
            PEFileReader peFile = _assembly.PEFileReader;
            MDTables mdScope = peFile.MetaData;
 
            mdScope.SeekToMDToken(_mdToken);
            peFile.B.ReadUInt32();  // TypeAttributes; 
            _typeName = mdScope.ReadString();  // this type's name 
            _nameSpace = mdScope.ReadString();  // this type's namespace
            _representation |= Representation.Name; 
        }

        internal TypeInfo(MetadataToken typeDef, MiniAssembly assembly, String typeName, String nameSpace)
        { 
            System.Diagnostics.Contracts.Contract.Requires(assembly != null);
            System.Diagnostics.Contracts.Contract.Requires(!String.IsNullOrEmpty(typeName)); 
            System.Diagnostics.Contracts.Contract.Requires(typeDef.Table == MDTables.Tables.TypeDef); 

            _mdToken = typeDef; 
            _assembly = assembly;
            _typeName = typeName;
            _nameSpace = nameSpace;
            _assemblyQualifiedName = FullTypeName + ", " + assembly.FullName; 
            _representation = Representation.Token | Representation.Name | Representation.AssemblyQualifiedName;
        } 
 
        internal TypeInfo(MetadataToken typeDef, MiniAssembly assembly, MiniModule module, String typeName, String nameSpace, bool isGeneric)
        { 
            System.Diagnostics.Contracts.Contract.Requires(assembly != null);
            System.Diagnostics.Contracts.Contract.Requires(module != null);
            System.Diagnostics.Contracts.Contract.Requires(!String.IsNullOrEmpty(typeName));
            System.Diagnostics.Contracts.Contract.Requires(typeDef.Table == MDTables.Tables.TypeDef); 

            _mdToken = typeDef; 
            _assembly = assembly; 
            _module = module;
            _typeName = typeName; 
            _nameSpace = nameSpace;
            _assemblyQualifiedName = FullTypeName + ", " + assembly.FullName;
            _representation = Representation.Token | Representation.Name | Representation.AssemblyQualifiedName;
            _isGeneric = isGeneric; 
        }
 
        internal String FullTypeName 
        {
            get { return String.IsNullOrEmpty(_nameSpace) ? _typeName : _nameSpace + "." + _typeName; } 
        }

        // security attributes are needed because of mscorlib.GetName() calls
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disambiguatingJunkForTypeRefOverload")] 
        [System.Security.SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2128:SecurityTransparentCodeShouldNotAssert", Justification = "This is a SecurityRules.Level1 assembly, in which this rule is being incorrectly applied")] 
        internal TypeInfo(MetadataToken typeRefToken, MiniAssembly referencingAssembly, bool disambiguatingJunkForTypeRefOverload) 
        {
            System.Diagnostics.Contracts.Contract.Requires(referencingAssembly != null); 
            System.Diagnostics.Contracts.Contract.Requires(typeRefToken.Table == MDTables.Tables.TypeRef);

            _mdToken = typeRefToken;
            _assembly = referencingAssembly; 
            _representation = Representation.TypeRef | Representation.Name;
 
            PEFileReader peFile = referencingAssembly.PEFileReader; 
            MDTables MetaData = peFile.MetaData;
            MetaData.SeekToMDToken(typeRefToken); 
            MetadataToken assemblyRef = MetaData.ReadMetadataToken(MDTables.Encodings.ResolutionScope);
            _typeName = MetaData.ReadString();
            _nameSpace = MetaData.ReadString();
 
            // Read assembly information
            MetaData.SeekToMDToken(assemblyRef); 
            UInt16 major = peFile.B.ReadUInt16(); 
            UInt16 minor = peFile.B.ReadUInt16();
            UInt16 build = peFile.B.ReadUInt16(); 
            UInt16 revision = peFile.B.ReadUInt16();
            peFile.B.ReadUInt32(); // assembly flags
            byte[] publicKeyOrToken = MetaData.ReadBlob();
            String simpleName = MetaData.ReadString(); 
            String culture = MetaData.ReadString();
 
            // assert so we can get the AssemblyName of mscorlib.dll 
            FileIOPermission permission = new FileIOPermission(PermissionState.None);
            permission.AllLocalFiles = FileIOPermissionAccess.PathDiscovery; 
            permission.Assert();

            System.Reflection.Assembly mscorlib = typeof(Object).Assembly;
            if (simpleName == "mscorlib" && (culture.Length == 0) && Utils.PublicKeyMatches(mscorlib.GetName(), publicKeyOrToken)) 
            {
                // Upgrade to using a Type! 
                Type t = mscorlib.GetType(FullName, false); 
                if (t != null)
                { 
                    _reflectionType = t;
                    _representation |= Representation.ReflectionType;
                }
            } 

            String typeRefDefiningAssemblyName = String.Format(CultureInfo.InvariantCulture, 
                "{0}, Version={1}.{2}.{3}.{4}, Culture={5}, PublicKeyToken={6}", 
                simpleName, major, minor, build, revision,
                (culture.Length == 0 ? "neutral" : culture), Utils.PublicKeyToString(publicKeyOrToken)); 
            _assemblyQualifiedName = FullName + ", " + typeRefDefiningAssemblyName;
            _representation |= Representation.AssemblyQualifiedName;
        }
 
        internal TypeInfo(Type type)
        { 
            System.Diagnostics.Contracts.Contract.Requires(type != null); 

            _reflectionType = type; 
            _assemblyQualifiedName = type.AssemblyQualifiedName;
            _isGeneric = type.ContainsGenericParameters || type.IsGenericType || type.GetGenericArguments().Length > 0;

            _typeName = type.Name; 
            _nameSpace = type.Namespace;
            if (_nameSpace == null) 
                _nameSpace = String.Empty; 
            _representation = Representation.Name | Representation.AssemblyQualifiedName | Representation.ReflectionType;
 
            System.Diagnostics.Contracts.Contract.Assert(_assembly == null);  // Don't do this, or we might serialize assemblies!
        }

        internal TypeInfo(SerializationInfo info, StreamingContext context) 
        {
            _assembly = (MiniAssembly) info.GetValue(AssemblyFieldName, typeof(MiniAssembly)); 
            _module = (MiniModule) info.GetValue(ModuleFieldName, typeof(MiniModule)); 
            _mdToken = (MetadataToken) info.GetValue(MDTokenFieldName, typeof(MetadataToken));
            _typeName = info.GetString(TypeNameFieldName); 
            _nameSpace = info.GetString(NameSpaceFieldName);
            _assemblyQualifiedName = info.GetString(AssemblyQualifiedFieldName);
            _representation = (Representation) info.GetInt32(RepresentationFieldName);
            System.Diagnostics.Contracts.Contract.Assert((_representation & Representation.ReflectionType) == 0); 
            _isGeneric = info.GetBoolean(IsGenericFieldName);
        } 
 
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        { 
            info.AddValue(AssemblyFieldName, _assembly);
            info.AddValue(ModuleFieldName, _module);
            info.AddValue(MDTokenFieldName, _mdToken);
            info.AddValue(TypeNameFieldName, _typeName); 
            info.AddValue(NameSpaceFieldName, _nameSpace);
            info.AddValue(AssemblyQualifiedFieldName, _assemblyQualifiedName); 
            Representation r = _representation & ~Representation.ReflectionType; 
            info.AddValue(RepresentationFieldName, r);
            info.AddValue(IsGenericFieldName, _isGeneric); 
        }

        internal static void SetWarnings(ICollection warnings)
        { 
            Warnings = warnings;
        } 
 
        internal Type ReflectionType
        { 
            get {
                System.Diagnostics.Contracts.Contract.Assert(HasReflectionType);
                return _reflectionType;
            } 
        }
 
        private bool HasAssemblyQualifiedName { 
            get { return (_representation & Representation.AssemblyQualifiedName) != 0; }
        } 

        private bool HasName {
            get { return (_representation & Representation.Name) != 0; }
        } 

        private bool HasToken 
        { 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Needed for Contracts conditional compilation")]
            get { return (_representation & Representation.Token) != 0; } 
        }

        internal bool HasReflectionType {
            [Pure] 
            get { return (_representation & Representation.ReflectionType) != 0; }
        } 
 
        private bool HasTypeRef {
            get { return (_representation & Representation.TypeRef) != 0; } 
        }

        internal MiniAssembly Assembly {
            get { 
                System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result() != null);
 
                // Do not store the assembly in this object - make sure it doesn't 
                // leak across appdomains, etc.
                MiniAssembly retVal = _assembly; 
                if (retVal == null)
                {
                    System.Diagnostics.Contracts.Contract.Assert(HasReflectionType);
                    retVal = new MiniAssembly(_reflectionType.Assembly); 
                }
                return retVal; 
            } 
        }
 
        /*
        internal bool IsClass {
            get {
                if (HasReflectionType) 
                    return _reflectionType.IsClass;
 
                if (HasTypeRef) { 
                    TypeInfo def = TypeRefToTypeDef(_mdToken, true);
                    return def.IsClass; 
                }

                Contract.Assert(HasToken);
                PEFileReader peFile = _assembly.PEFileReader; 
                MDTables mdScope = peFile.MetaData;
                mdScope.SeekToMDToken(_mdToken); 
                System.Reflection.TypeAttributes attrs = (System.Reflection.TypeAttributes)peFile.B.ReadUInt32();  // TypeAttributes; 
                return (attrs & System.Reflection.TypeAttributes.Class) != 0;
            } 
        }
        */

        internal bool IsGeneric { 
            get { return _isGeneric; }
        } 
 
        public bool IsInterface {
            get { 
                if (HasReflectionType)
                    return _reflectionType.IsInterface;

                if (HasTypeRef) { 
                    TypeInfo def = TypeRefToTypeDef(_mdToken, true);
                    return def.IsInterface; 
                } 

                System.Diagnostics.Contracts.Contract.Assert(HasToken); 
                PEFileReader peFile = _assembly.PEFileReader;
                MDTables mdScope = peFile.MetaData;
                mdScope.SeekToMDToken(_mdToken);
                System.Reflection.TypeAttributes attrs = (System.Reflection.TypeAttributes) peFile.B.ReadUInt32();  // TypeAttributes; 
                return (attrs & System.Reflection.TypeAttributes.Interface) != 0;
            } 
        } 

        /* 
        public bool IsMarshalByRef {
            get {
                if (HasReflectionType)
                    return _reflectionType.IsMarshalByRef; 
                throw new NotImplementedException("TypeInfo::IsMarshalByRef on non-Reflection types is not implemented");
            } 
        } 

        public bool IsSealed { 
            get {
                if (HasReflectionType)
                    return _reflectionType.IsSealed;
 
                if (HasTypeRef) {
                    TypeInfo def = TypeRefToTypeDef(_mdToken, true); 
                    return def.IsSealed; 
                }
 
                Contract.Assert(HasToken);
                PEFileReader peFile = _assembly.PEFileReader;
                MDTables mdScope = peFile.MetaData;
                mdScope.SeekToMDToken(_mdToken); 
                System.Reflection.TypeAttributes attrs = (System.Reflection.TypeAttributes)peFile.B.ReadUInt32();  // TypeAttributes;
                return (attrs & System.Reflection.TypeAttributes.Sealed) != 0; 
            } 
        }
        */ 

        public String Name
        {
            get { 
                System.Diagnostics.Contracts.Contract.Assert(HasName);
                return _typeName; 
            } 
        }
 
        public String FullName {
            get {
                System.Diagnostics.Contracts.Contract.Assert(HasName);
                if (String.IsNullOrEmpty(_nameSpace)) 
                    return _typeName;
                return _nameSpace + "." + _typeName; 
            } 
        }
 
        public String AssemblyQualifiedName {
            get {
                System.Diagnostics.Contracts.Contract.Assert(HasName);
                if (HasAssemblyQualifiedName) 
                    return _assemblyQualifiedName;
 
                System.Diagnostics.Contracts.Contract.Assert(!HasTypeRef); 

                if (HasName) { 
                    _assemblyQualifiedName = FullName + ", " + _assembly.FullName;
                    _representation |= Representation.AssemblyQualifiedName;
                    return _assemblyQualifiedName;
                } 

                throw new NotImplementedException(); 
            } 
        }
 
        public String AssemblyName {
            get {
                System.Diagnostics.Contracts.Contract.Assert(_assembly != null || HasAssemblyQualifiedName);
 
                if (HasAssemblyQualifiedName)
                { 
                    int firstComma = _assemblyQualifiedName.IndexOf(','); 
                    return _assemblyQualifiedName.Substring(firstComma + 2);
                } 
                else
                {
                    System.Diagnostics.Contracts.Contract.Assert(_assembly != null);
                    String asmName = _assembly.FullName; 
                    _assemblyQualifiedName = FullName + ", " + _assembly.FullName;
                    _representation |= Representation.AssemblyQualifiedName; 
                    return asmName; 
                }
            } 
        }

        public TypeInfo BaseType {
            get { 

                if (HasTypeRef) 
                { 
                    TypeInfo defInfo = TypeRefToTypeDef(_mdToken, true);
                    return defInfo.BaseType; 
                }

                System.Diagnostics.Contracts.Contract.Assert(HasToken);
                System.Diagnostics.Contracts.Contract.Assert(!HasTypeRef); 
                PEFileReader peFile = _assembly.PEFileReader;
                MDTables mdScope = peFile.MetaData; 
 
                mdScope.SeekToMDToken(_mdToken);
                peFile.B.ReadUInt32();  // TypeAttributes; 
                if (HasName) {
                    mdScope.ReadStringIndex();  // this type's name
                    mdScope.ReadStringIndex();  // this type's namespace
                } 
                else {
                    _typeName = mdScope.ReadString();  // this type's name 
                    _nameSpace = mdScope.ReadString();  // this type's namespace 
                    _representation |= Representation.Name;
                } 

                MetadataToken baseClass = peFile.MetaData.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);
                return TypeInfoFromTypeDefOrRef(baseClass);
            } 
        }
 
        private TypeInfo TypeInfoFromTypeDefOrRef(MetadataToken token) 
        {
            if (token.Table == MDTables.Tables.TypeRef) 
            {
                // Call our TypeRef constructor.  The HAV will be in another assembly.
                return new TypeInfo(token, _assembly, false);
            } 
            else if (token.Table == MDTables.Tables.TypeDef)
            { 
                // The base is defined in this same assembly, not in the separate HAV. 
                return new TypeInfo(token, _assembly);
            } 
            // else it is a TypeSpec -- a generic type

            throw new GenericsNotImplementedException();
        } 

 
        public MiniConstructorInfo[] GetConstructors() 
        {
            return GetConstructors(false); 
        }

        public MiniConstructorInfo[] GetConstructors(bool includePrivate)
        { 
            System.Diagnostics.Contracts.Contract.Assert(HasToken/* || HasReflectionType*/, "GetConstructors needs a token (or you should uncomment the support for Reflection types)");
 
            List ctors = new List(); 

            /* 
            if (HasReflectionType) {
                System.Reflection.BindingFlags visibility = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public;
                if (includePrivate)
                    visibility |= System.Reflection.BindingFlags.NonPublic; 
                foreach (System.Reflection.ConstructorInfo ctor in _reflectionType.GetConstructors(visibility))
                    ctors.Add(new MiniConstructorInfo(ctor)); 
                return ctors.ToArray(); 
            }
             */ 

            System.Diagnostics.Contracts.Contract.Assert(_mdToken.Table == MDTables.Tables.TypeDef);

            PEFileReader peFile = _assembly.PEFileReader; 
            peFile.InitMetaData();
            MDTables MetaData = peFile.MetaData; 
 
            MetaData.SeekToMDToken(_mdToken);
            System.Reflection.TypeAttributes flags = (System.Reflection.TypeAttributes) peFile.B.ReadUInt32(); 
            System.Reflection.TypeAttributes vis = System.Reflection.TypeAttributes.VisibilityMask & flags;
            bool isPublic = (vis == System.Reflection.TypeAttributes.Public); // don't support NestedPublic
            if (!includePrivate && !isPublic)
                return new MiniConstructorInfo[0]; 
            MetaData.ReadStringIndex();  // typename
            MetaData.ReadStringIndex();  // namespace 
 
            MetadataToken baseClass = MetaData.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);  // Base class
            uint firstMemberIndex = MetaData.ReadRowIndex(MDTables.Tables.FieldDef); // Field list 
            uint firstMethodIndex = MetaData.ReadRowIndex(MDTables.Tables.MethodDef);  // Method list
            uint lastMethodIndex;
            // If this is the last entry in the TypeDef table, then all the rest of the methods in the MethodDef
            // table belong to this type.  Otherwise, look for the methods belonging to the next type. 
            if (_mdToken.Index == MetaData.RowsInTable(MDTables.Tables.TypeDef))
            { 
                lastMethodIndex = MetaData.RowsInTable(MDTables.Tables.MethodDef); 
            }
            else 
            {
                MetaData.SeekToRowOfTable(MDTables.Tables.TypeDef, _mdToken.Index);  // Seek to next type (not off by 1!)
                peFile.B.ReadUInt32(); // Flags
                MetaData.ReadStringIndex();  // type name 
                MetaData.ReadStringIndex();  // namespace
                MetaData.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);  // Next type's base class 
                MetaData.ReadRowIndex(MDTables.Tables.FieldDef);  // field list; 
                uint firstMethodOfNextType = MetaData.ReadRowIndex(MDTables.Tables.MethodDef);  // method list
                lastMethodIndex = firstMethodOfNextType - 1; 
            }

            // Now walk through list of methods, looking for ones w/ the name ".ctor".
            for (uint i = firstMethodIndex; i <= lastMethodIndex; i++) 
            {
                MetadataToken method = new MetadataToken(MDTables.Tables.MethodDef, i); 
                MetaData.SeekToMDToken(method); 
                UInt32 rva = peFile.B.ReadUInt32();
                UInt16 implFlags = peFile.B.ReadUInt16();  // MethodImplAttributes 
                System.Reflection.MethodAttributes attrs = (System.Reflection.MethodAttributes)peFile.B.ReadUInt16();  // Flags - MethodAttributes
                // Visibility check
                if (!includePrivate && (attrs & System.Reflection.MethodAttributes.Public) == 0)
                    continue; 
                String methodName = MetaData.ReadString();  // Name
                // @ 
                if (!String.Equals(methodName, ".ctor")) 
                    continue;
 
                byte[] sig = MetaData.ReadBlob();
                try
                {
                    MiniParameterInfo[] parameters = ParseSig(sig); 
                    ctors.Add(new MiniConstructorInfo(parameters));
                } 
                catch (GenericsNotImplementedException) 
                {
                    // may be caused by a Generic contract.  The user will be warned elsewhere that generic contracts are not supported. 
                    /*
                    if (Warnings != null) {
                        lock (Warnings) {
                            Warnings.Add(String.Format(CultureInfo.CurrentCulture, Res.UnparsibleConstructorSignature, this.Name, e.GetType().Name, e.Message)); 
                        }
                    } 
                    */ 
                }
            } // for each .ctor 
            return ctors.ToArray();
        }

        // See the ECMA CLI spec, Partition II, section 23.2.1. 
        private MiniParameterInfo[] ParseSig(byte[] sig)
        { 
            PEFileReader peFile = _assembly.PEFileReader; 
            peFile.InitMetaData();
            MDTables MetaData = peFile.MetaData; 

            uint i = 0;
            // The first byte of the Signature holds bits for HASTHIS, EXPLICITTHIS
            // and calling convention (DEFAULT, VARARG, or GENERIC). These are OR'ed 
            // together.
            i++; 
 
            uint numParams = DecodeInteger(sig, ref i);
 
            // Skip over return type
            //   Skip custom modifiers.
            do
            { 
                if (sig[i] == (byte) CorElementType.CModOpt) i++;
                else if (sig[i] == (byte) CorElementType.CModReqd) i++; 
                else break; 
            } while (true);
            //   Skip return type.  Note that for constructors, it should be void. 
            if (sig[i] == (byte) CorElementType.Void) i++;
            else if (sig[i] == (byte) CorElementType.TypedByRef) i++;
            else
            { 
                if (sig[i] == (byte) CorElementType.ByRef) i++;
                ParseType(sig, ref i, false, true); 
            } 

            MiniParameterInfo[] parameters = new MiniParameterInfo[numParams]; 
            for (uint paramNum = 0; paramNum < numParams; paramNum++)
            {
                parameters[paramNum] = ParseType(sig, ref i, false, false);
                //Console.WriteLine("Read a parameter: {0}", parameters[paramNum]); 
            }
            return parameters; 
        } 

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="bogus warning")] 
        private MiniParameterInfo ParseType(byte[] sig, ref uint i,
                     bool allowTypedByRef, bool allowVoid)
        {
            CorElementType b = (CorElementType) sig[i++]; 
            switch (b)
            { 
                case CorElementType.Boolean: 
                case CorElementType.Char:
                case CorElementType.I1: 
                case CorElementType.U1:
                case CorElementType.I2:
                case CorElementType.U2:
                case CorElementType.I4: 
                case CorElementType.U4:
                case CorElementType.I8: 
                case CorElementType.U8: 
                case CorElementType.R4:
                case CorElementType.R8: 
                case CorElementType.I:
                case CorElementType.U:
                case CorElementType.String:
                case CorElementType.Object: 
                    return new MiniParameterInfo(b);
 
                case CorElementType.TypedByRef: 
                    //AddPrimitiveTypeName((Int32)B, SB);
                    if (!allowTypedByRef) throw new BadImageFormatException(Res.TypedByRefNotAllowed);//TypedByRef not allowed here 
                    throw new NotImplementedException();

                case CorElementType.Void:
                    if (!allowVoid) throw new BadImageFormatException(); 
                    return new MiniParameterInfo(b);
 
                case CorElementType.Class: 
                case CorElementType.ValueType:
                    return new MiniParameterInfo(b, ParseTypeDefRefOrSpec(sig, ref i)); 

                case CorElementType.Ptr:
                    // PTR CustomMod* VOID | PTR CustomMod* Type;
                    /* 
                    AddCustomMods(Bytes, ref i, SB);
                    SB.Append("Ptr to "); 
                    AddType(Bytes, ref i, SB, false, true);   // VOID is allowed here 
                     */
                    throw new NotImplementedException(); 

                case CorElementType.FnPtr:
                    // FNPTR MethodDefSig | FNPTR MethodRefSig;
                    //AddMethodSig(Bytes, ref i, SB); 
                    throw new NotImplementedException();
                case CorElementType.SzArray: 
                    //AddSzArray(Bytes, ref i, SB); 
                    throw new NotImplementedException();
                case CorElementType.Array: 
                    //AddArray(Bytes, ref i, SB);
                    throw new NotImplementedException();
                case CorElementType.ByRef:
                    throw new NotImplementedException(); 
                case CorElementType.GenericInst:
                    // may be caused by the contract being a generic type 
                    throw new GenericsNotImplementedException(); 
                case CorElementType.Var:
                    throw new NotImplementedException(); 

                default:
                    System.Diagnostics.Contracts.Contract.Assert(false, "Unrecognized CorElementType");
                    throw new BadImageFormatException(String.Format(CultureInfo.CurrentCulture, Res.UnrecognizedCorElementType, b)); 
            }
        } 
 
        private TypeInfo ParseTypeDefRefOrSpec(byte[] sig, ref uint i)
        { 
            // The encoded version of this TypeRef token is made follows up:
            // 1. encode the table that this token the indexes least significant 2 bits.
            //    The bit values to use are 0, 1 and 2, specifying the target table is the
            //    TypeDef, TypeRef or TypeSpec table, respectively 
            // 2. shift the 3-byte row index (0x000012 in this example) left by 2 bits
            //    and OR into the 2-bit encoding from step 1; 
            // 3. compress the resulting value (see Section 22.2) 
            uint compressed = DecodeInteger(sig, ref i);
            uint tableCode = compressed & 0x3; 
            uint index = (uint) ((compressed & (~0x3)) / 4);
            MDTables.Tables[] mapToTable = new MDTables.Tables[]{MDTables.Tables.TypeDef, MDTables.Tables.TypeRef, MDTables.Tables.TypeSpec};

            MetadataToken token = new MetadataToken(mapToTable[tableCode], index); 
            switch (tableCode)
            { 
                case 0:  // TypeDef 
                    return new TypeInfo(token, _assembly);
 
                case 1:  // TypeRef
                    return new TypeInfo(token, _assembly, false);  // TypeRef-specific constructor.

                case 2:  // TypeSpec 
                    throw new NotImplementedException();
 
                default: 
                    throw new BadImageFormatException(Res.InvalidMetadataToken);
            } 
        }

        private static UInt32 DecodeInteger(byte[] bytes, ref uint i)
        { 
            UInt32 b = bytes[i];
            i += 1; 
            if ((b & 0x80) == 0) return b; 
            else if ((b & 0xC0) == 0x80)
            { 
                UInt32 nextB = bytes[i];
                i += 1;
                return ((b & 0x7F) * 0x100) | nextB;
            } 
            else if ((b & 0xE0) == 0xC0)
            { 
                UInt32 nextB, afterNext, final; 
                nextB = bytes[i];
                afterNext = bytes[i + 1]; 
                final = bytes[i + 2];
                i += 3;
                return ((b & 0x1F) * 0x100000) | (nextB * 0x10000) |
                       (afterNext * 0x100) | final; 
            }
            else throw new ArgumentOutOfRangeException("bytes", 
                              b, Res.CodedIntegerTooLong);// "Coded integer more than 4 bytes long"); 
        }
 
        public bool Implements(TypeInfo ifaceType)
        {
            System.Diagnostics.Contracts.Contract.Requires(ifaceType != null);
            System.Diagnostics.Contracts.Contract.Assert(HasToken || HasReflectionType || HasTypeRef); 

            if (HasReflectionType) 
            { 
                System.Diagnostics.Contracts.Contract.Assert(ifaceType.HasAssemblyQualifiedName);
                foreach(Type implementsIFace in _reflectionType.GetInterfaces()) 
                    if (Utils.FullTypeNameDefEqualsDef(implementsIFace.AssemblyQualifiedName, ifaceType.AssemblyQualifiedName))
                        return true;
                return false;
            } 

            // This can be a typeref.  ---- the other assembly to parse this. 
            // I need to support the HAV in assembly A, the HA in B, the specific contract 
            // interface in assembly C, and IContract in assembly D.  I'm inspecting the HA,
            // and I'll get a typeref for C, and I need to make sure it implements IContract in D. 

            PEFileReader peFile = _assembly.PEFileReader;
            peFile.InitMetaData();
            MDTables thisMetaData = peFile.MetaData; 

            if (_mdToken.Table == MDTables.Tables.TypeRef) 
            { 
                TypeInfo def = TypeRefToTypeDef(_mdToken, true);
                return def.ImplementsHelper(def._assembly.PEFileReader, def._mdToken, ifaceType); 
            }
            else
            {
                System.Diagnostics.Contracts.Contract.Assert(_mdToken.Table == MDTables.Tables.TypeDef); 
                throw new NotImplementedException();
            } 
        } 

        // Does a given typedef in the specified PE file implement the specified interface? 
        private bool ImplementsHelper(PEFileReader peFile, MetadataToken typeDefToken, TypeInfo ifaceType)
        {
            System.Diagnostics.Contracts.Contract.Requires(typeDefToken.Table == MDTables.Tables.TypeDef);
 
            MDTables mdScope = peFile.MetaData;
 
            // Walk through all rules of the interface implementation table, 
            // looking for this typeDefToken.  If we find it, check to see if
            // that row says this type implements the specified interface. 
            // If not, continue walking the interface impl table.
            uint numRows = mdScope.RowsInTable(MDTables.Tables.InterfaceImpl);
            for (uint i = 0; i < numRows; i++)
            { 
                mdScope.SeekToRowOfTable(MDTables.Tables.InterfaceImpl, i);
                uint typeDefRow = mdScope.ReadRowIndex(MDTables.Tables.TypeDef); 
                if (typeDefRow == typeDefToken.Index) 
                {
                    // if we implement it, return true.  Else continue. 
                    MetadataToken interfaceToken = mdScope.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);
                    if (ifaceType.HasName)
                    {
                        mdScope.SeekToMDToken(interfaceToken); 
                        // Interface for IContract should be a typeref.
                        switch (interfaceToken.Table) 
                        { 
                            case MDTables.Tables.TypeRef:
                                { 
                                    MetadataToken resolutionScope = mdScope.ReadMetadataToken(MDTables.Encodings.ResolutionScope);
                                    String ifaceName = mdScope.ReadString();
                                    if (!String.Equals(ifaceName, ifaceType._typeName))
                                        continue; 
                                    String ifaceNameSpace = mdScope.ReadString();
                                    if (!String.Equals(ifaceNameSpace, ifaceType._nameSpace)) 
                                        continue; 
                                    if (MiniAssembly.Equals(ifaceType.Assembly, peFile, resolutionScope))
                                        return true; 
                                    break;
                                }

                            case MDTables.Tables.TypeDef: 
                                {
                                    // This type implements an interface defined in the same assembly. 
                                    // This isn't really interesting for the add-in model, based on what 
                                    // we've currently designed and our limited use of this class.
                                    mdScope.B.ReadUInt32();  // TypeAttributes 
                                    String ifaceName = mdScope.ReadString();
                                    if (!String.Equals(ifaceName, ifaceType._typeName))
                                        continue;
                                    String ifaceNameSpace = mdScope.ReadString(); 
                                    if (!String.Equals(ifaceNameSpace, ifaceType._nameSpace))
                                        continue; 
                                    if (this._assembly.Equals(ifaceType._assembly)) 
                                        return true;
                                    break; 
                                }

                            case MDTables.Tables.TypeSpec:
                                // Since we're only looking for IContract, which is non-generic, 
                                // we should ignore this row and move on.
                                System.Diagnostics.Contracts.Contract.Assert(false, "Checking whether a type implements a TypeSpec is NYI (generic interface?)"); 
                                break; 

                            default: 
                                System.Diagnostics.Contracts.Contract.Assert(false, "Support for this interface type is NYI");
                                throw new NotImplementedException(String.Format(CultureInfo.CurrentCulture, Res.UnsupportedInterfaceType, interfaceToken.Table));
                        }
                    } 
                    else
                    { 
                        throw new NotImplementedException(); 
                    }
                } 
            }
            return false;
        }
 

        internal TypeInfo TypeRefToTypeDef(MetadataToken typeRef, bool throwOnError) 
        { 
            System.Diagnostics.Contracts.Contract.Requires(typeRef.Table == MDTables.Tables.TypeRef);
 
            PEFileReader peFile = _assembly.PEFileReader;
            peFile.InitMetaData();
            MDTables thisMetaData = peFile.MetaData;
            thisMetaData.SeekToMDToken(_mdToken); 
            MetadataToken resolutionScope = thisMetaData.ReadMetadataToken(MDTables.Encodings.ResolutionScope);
            String refTypeName = thisMetaData.ReadString();  // Name 
            String refNamespace = thisMetaData.ReadString();  // Namespace 
            System.Diagnostics.Contracts.Contract.Assert(resolutionScope.Table == MDTables.Tables.AssemblyRef);
            MiniAssembly definingAssembly = _assembly.ResolveAssemblyRef(resolutionScope, throwOnError); 
            if (definingAssembly != null) {
                return definingAssembly.FindTypeInfo(refTypeName, refNamespace);
            }
            return null; 
        }
 
        internal TypeInfo TryGetTypeDef() 
        {
            //If the type came from mscorlib (e.g. MarshalByRefObject) then we have a reflection type. 
            //Currently we just return null in this case, but if we later support arbitrary AddInBase classes
            //then we should return the real typedef
            if (HasReflectionType)
                return null; 

            if (HasTypeRef) 
                return TypeRefToTypeDef(_mdToken, false); 

            return this; 
        }

        // Get the immediate interfaces on this type.
        public TypeInfo[] GetInterfaces() 
        {
            List interfaces = new List(); 
            if (HasReflectionType) 
            {
                foreach (Type interfaceType in _reflectionType.GetInterfaces()) 
                    interfaces.Add(new TypeInfo(interfaceType));
            }
            else if (HasTypeRef)
            { 
                TypeInfo defInfo = TypeRefToTypeDef(_mdToken, true);
                return defInfo.GetInterfaces(); 
            } 
            else
            { 
                System.Diagnostics.Contracts.Contract.Assert(_mdToken.Table == MDTables.Tables.TypeDef);

                PEFileReader peFile = _assembly.PEFileReader;
                MDTables mdScope = peFile.MetaData; 

                // Walk through all rows of the interface implementation table, 
                // looking for this _mdToken. 
                uint numRows = mdScope.RowsInTable(MDTables.Tables.InterfaceImpl);
                for (uint i = 0; i < numRows; i++) 
                {
                    try
                    {
                        mdScope.SeekToRowOfTable(MDTables.Tables.InterfaceImpl, i); 
                        uint typeDefRow = mdScope.ReadRowIndex(MDTables.Tables.TypeDef);
                        if (typeDefRow == _mdToken.Index) 
                        { 
                            MetadataToken interfaceToken = mdScope.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);
                            interfaces.Add(TypeInfoFromTypeDefOrRef(interfaceToken)); 
                        }
                    }
                    catch (GenericsNotImplementedException)  // ignore interfaces such as IComparable that aren't relevant to the addin model
                    {} 
                }
            } 
            return interfaces.ToArray(); 
        }
 
        public override bool Equals(object obj)
        {
            TypeInfo that = obj as TypeInfo;
            if (that == null) 
                return false;
            return this.Equals(that); 
        } 

        public bool Equals(TypeInfo value) 
        {
            if (value == null)
                return false;
 
            String thisType = AssemblyQualifiedName;
            String thatType = value.AssemblyQualifiedName; 
 
            bool r = Utils.FullTypeNameDefEqualsDef(thisType, thatType);
            return r; 
        }

        public override int GetHashCode()
        { 
            System.Diagnostics.Contracts.Contract.Assert(HasName);
            return AssemblyQualifiedName.GetHashCode(); 
        } 

        public override String ToString() 
        {
            if (_typeName != null)
                return _nameSpace + "::" + _typeName;
            else 
                return "MD Token: " + _mdToken.ToString();
        } 
 

        // Return the attributes on this type of the given custom attribute type 
        internal MiniCustomAttributeInfo[] GetCustomAttributeInfos(Type caReflectedType)
        {
            List result = new List();
 
            PEFileReader peFile = _assembly.PEFileReader;
            peFile.InitMetaData(); 
            MDTables metaData = peFile.MetaData; 

            uint numRows = metaData.RowsInTable(MDTables.Tables.CustomAttribute); 
            for (uint i = 0; i < numRows; i++)
            {
                metaData.SeekToRowOfTable(MDTables.Tables.CustomAttribute, i);
 
                // Format: Parent type token, CA type token (really the constructor method), value (index into blob heap)
                MetadataToken targetType = metaData.ReadMetadataToken(MDTables.Encodings.HasCustomAttribute); 
                MetadataToken caType = metaData.ReadMetadataToken(MDTables.Encodings.CustomAttributeType); 
                byte[] caBlob = metaData.ReadBlob();
 
                if (targetType.Equals(this._mdToken)) {
                    //Console.WriteLine("CA - Applied to: {0}  CA .ctor: {1}  Value: {2}", targetType, caType, value);
                    //Console.WriteLine("CA MD Tokens  Parent: {0}  Type: {1}", targetType.ToMDToken(), caType.ToMDToken());
 
                    // Ensure the custom attribute type is the type we expect
                    metaData.SeekToMDToken(caType); 
                    String caTypeName = null, caNameSpace = null; 
                    if (caType.Table != MDTables.Tables.MemberRef)
                    { 
                        // Custom attribute was defined in the assembly we are currently inspecting?
                        // Ignore it.
                        System.Diagnostics.Contracts.Contract.Assert(caType.Table == MDTables.Tables.MethodDef);
                        continue; 
                    }
 
                    MetadataToken customAttributeType = metaData.ReadMetadataToken(MDTables.Encodings.MemberRefParent); 

                    //Console.WriteLine("   MemberRef: {0}  Type of MemberRef: {1}", caType.ToMDToken(), customAttributeType.ToMDToken()); 
                    metaData.SeekToMDToken(customAttributeType);
                    MetadataToken resolutionScope = metaData.ReadMetadataToken(MDTables.Encodings.ResolutionScope);
                    caTypeName = metaData.ReadString();
                    caNameSpace = metaData.ReadString(); 

                    if (caTypeName == caReflectedType.Name && caNameSpace == caReflectedType.Namespace) { 
                        MiniCustomAttributeInfo customAttributeInfo = ParseCustomAttribute(caBlob, caReflectedType); 
                        result.Add(customAttributeInfo);
                    } 
                }
            }
            return result.ToArray();
        } 

        private static MiniCustomAttributeInfo ParseCustomAttribute(byte[] caBlob, Type caReflectedType) 
        { 
            uint b = 2;  //skip prolog
 
            System.Reflection.BindingFlags visibility = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public;
            List fixedArgs = new List();

            // to support multiple constructors we would need to look up the exact one in the method table 
            System.Reflection.ConstructorInfo[] ctors = caReflectedType.GetConstructors(visibility);
            if (ctors.Length > 1) 
                throw new NotImplementedException(); 

            System.Reflection.ConstructorInfo ctor = ctors[0]; 
            foreach(System.Reflection.ParameterInfo parameterInfo in ctor.GetParameters())
            {
                if (parameterInfo.ParameterType == typeof(String))
                { 
                    String fixedParamString = ReadSerString(caBlob, ref b);
                    fixedArgs.Add(new MiniCustomAttributeFixedArgInfo(fixedParamString)); 
                } 
                else
                    throw new NotImplementedException(); 
            }

            byte low = caBlob[b++];
            byte high = caBlob[b++]; 

            int numNamed = (high * 0x100) | low; 
 
            List namedArgs = new List();
            for (int j=0; j < numNamed; j++) 
            {
                String propName, value;
                ReadNamedArg(caBlob, ref b, out propName, out value);
 
                namedArgs.Add(new MiniCustomAttributeNamedArgInfo(CorElementType.String, propName, value));
            } 
 
            return new MiniCustomAttributeInfo(caReflectedType.Name, fixedArgs.ToArray(), namedArgs.ToArray());
        } 

        private static string ReadSerString(byte[] bytes, ref uint b)
        {
            if (bytes[b] == 0xFF) 
            {
                b++; 
                return null; 
            }
            uint len = DecodeInteger(bytes, ref b); 
            String result = s_encoder.GetString(bytes, (int)b, (int)len);
            b+= len;
            return result;
        } 

        private static void ReadNamedArg(byte[] bytes, ref uint b, out String name, out String value) 
        { 
            int fieldOrProperty = bytes[b++];
            int fieldOrPropType = bytes[b++]; 

            if (fieldOrPropType != (int)CorElementType.String)
                throw new NotImplementedException();
 
            String fieldOrPropName = ReadSerString(bytes, ref b);
            name = fieldOrPropName; 
 
            String fixedArg = ReadSerString(bytes, ref b);
            value = fixedArg; 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK