ReflectionHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Base / System / Windows / Markup / ReflectionHelper.cs / 2 / ReflectionHelper.cs

                            //------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2006
// 
//  File: TypeConverterHelper.cs
// 
//  Description: Specifies that the whitespace surrounding an element should be trimmed. 
//
//--------------------------------------------------------------------------- 

using System;
using System.IO;
using System.Reflection; 
using System.Diagnostics;
using System.Collections; 
using System.Collections.Generic; 
using System.ComponentModel;
using System.Globalization; 
using System.Runtime.CompilerServices;
using MS.Internal;
using MS.Utility;
 
#if PBTCOMPILER
namespace MS.Internal.Markup 
#else 
using MS.Internal.WindowsBase;
 
namespace System.Windows.Markup
#endif
{
 
    /// 
    /// Class that provides helper functions for the parser to reflect on types, properties, 
    /// custom attributes and load assemblies. 
    /// 
    internal static class ReflectionHelper 
    {
#region Type
        /// 
        /// Parse and get the type of the passed in string 
        /// 
        internal static Type GetQualifiedType(string typeName) 
        { 
            //
 
            string[] nameFrags = typeName.Split(new Char[] { ',' }, 2);
            Type type = null;
            if (nameFrags.Length == 1)
            { 
                // treat it as an absolute name
                type = Type.GetType(nameFrags[0]); 
            } 
            else
            { 
                if (nameFrags.Length != 2)
                    throw new InvalidOperationException(SR.Get(SRID.QualifiedNameHasWrongFormat, typeName));

                Assembly a = null; 
                try
                { 
                    a = LoadAssembly(nameFrags[1].TrimStart(), null); 
                }
                // ifdef magic to save compiler update. 
                // the fix below is for an FxCop rule about non-CLR exceptions.
                // however this rule has now been removed.
                catch (Exception e)   // Load throws generic Exceptions, so this can't be made more specific.
                { 
                    if (CriticalExceptions.IsCriticalException(e))
                    { 
                        throw; 
                    }
                    else 
                    {
                        // If we can't load the assembly, just return null (fall-through).
                        a = null;
                    } 
                }
 
                if (a != null) 
                {
                    try 
                    {
                        type = a.GetType(nameFrags[0]);
                        // If we can't get the type, just return null (fall-through).
                    } 
                    catch (ArgumentException)
                    { 
                        a = null; 
                    }
                    catch (System.Security.SecurityException) 
                    {
                        a = null;
                    }
                } 
            }
 
            return type; 
        }
 
        internal static bool IsNullableType(Type type)
        {
            return (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>)));
        } 

        internal static bool IsInternalType(Type type) 
        { 
            Type origType = type;
            Debug.Assert(null != type, "Type passed to IsInternalType is null"); 

            // If this is an internal nested type or a parent nested public type, walk up the declaring types.
            while (type.IsNestedAssembly || type.IsNestedFamORAssem || (origType != type && type.IsNestedPublic))
            { 
                type = type.DeclaringType;
            } 
 
            // If we're on a non-internal nested type, IsNotPublic & IsPublic will both return false.
            // If we were originally on a nested type and have currently reached a parent 
            // top-level(non nested) type, then it must be top level internal or public type.
            return type.IsNotPublic || (origType != type && type.IsPublic);
        }
 
        /// 
        /// Helper for determine if the type is a public class. 
        ///  
        /// Type to check
        /// True if type is public 
        internal static bool IsPublicType(Type type)
        {
            Debug.Assert(null != type, "Type passed to IsPublicType is null");
 
            // If this is a nested internal type, walk up the declaring types.
            while (type.IsNestedPublic) 
            { 
                type = type.DeclaringType;
            } 

            // If we're on a non-public nested type, IsPublic will return false.
            return type.IsPublic;
        } 

        // Since System.dll may be loaded in regular load context as well ROL context 
        // we need to get the ROL type from teh real type to compare a type with at compile 
        // time. At run-time, the same type can be used.
        internal static Type GetSystemType(Type type) 
        {
#if PBTCOMPILER
            Assembly asmSystem = LoadAssembly("System", null);
 
            if (asmSystem != null)
            { 
                type = asmSystem.GetType(type.FullName); 
            }
            else 
            {
                type = null;
            }
#endif 
            return type;
        } 
 
#endregion Type
 
        #region Attributes

        internal static string GetTypeConverterAttributeData(Type type, out Type converterType)
        { 
            bool foundTC = false;
            return GetCustomAttributeData(type, GetSystemType(typeof(TypeConverterAttribute)), true, ref foundTC, out converterType); 
        } 

        internal static string GetTypeConverterAttributeData(MemberInfo mi, out Type converterType) 
        {
            return GetCustomAttributeData(mi, GetSystemType(typeof(TypeConverterAttribute)), out converterType);
        }
 
        // Given a ReflectionOnlyLoaded member, returns the value of a metadata attribute of
        // Type attrType if set on that member. Looks only for attributes that have a ctor with 
        // one parameter that is of Type string or Type. 
        private static string GetCustomAttributeData(MemberInfo mi, Type attrType, out Type typeValue)
        { 
            IList list = CustomAttributeData.GetCustomAttributes(mi);
            string attrValue = GetCustomAttributeData(list, attrType, out typeValue, true, false);
            return attrValue == null ? string.Empty : attrValue;
        } 

#if PBTCOMPILER 
        // Given a ReflectionOnlyLoaded type, returns the value of a metadata attribute of 
        // Type attrType if set on that type. Looks only for attributes that have a ctor with
        // one parameter that is of Type string. 
        internal static string GetCustomAttributeData(Type t, Type attrType, bool allowZeroArgs)
        {
            Type typeValue = null;
            IList list = CustomAttributeData.GetCustomAttributes(t); 
            return GetCustomAttributeData(list, attrType, out typeValue, false, allowZeroArgs);
        } 
#endif 

        // Helper that enumerates a list of CustomAttributeData obtained via ReflectionOnlyLoad, and 
        // looks for a specific attribute of Type attrType. It only looks for attribiutes with a single
        // value of Type string that is passed in via a ctor. If allowTypeAlso is true, then it looks for
        // values of typeof(Type) as well.
        private static string GetCustomAttributeData(IList list, Type attrType, out Type typeValue, bool allowTypeAlso, bool allowZeroArgs) 
        {
            typeValue = null; 
            string attrValue = null; 
            for (int j = 0; j < list.Count; j++)
            { 
                attrValue = GetCustomAttributeData(list[j], attrType, out typeValue, allowTypeAlso, false, allowZeroArgs);
                if (attrValue != null)
                {
                    break; 
                }
            } 
 
            return attrValue;
        } 

        // Special version of type-based GetCustomAttributeData that does two
        //  additional tasks:
        //  1) Retrieves the attributes even if it's defined on a base type, and 
        //  2) Distinguishes between "attribute found and said null" and
        //     "no attribute found at all" via the ref bool. 
        internal static string GetCustomAttributeData(Type t, 
                                                      Type attrType,
                                                      bool allowTypeAlso, 
                                                  ref bool attributeDataFound,
                                                  out Type typeValue)
        {
            typeValue = null; 
            attributeDataFound = false;
            Type currentType = t; 
            string attributeDataString = null; 
            CustomAttributeData cad;
 
            while (currentType != null && !attributeDataFound)
            {
                IList list = CustomAttributeData.GetCustomAttributes(currentType);
 
                for (int j = 0; j < list.Count && !attributeDataFound; j++)
                { 
                    cad = list[j]; 

                    if (cad.Constructor.ReflectedType == attrType) 
                    {
                        attributeDataFound = true;
                        attributeDataString = GetCustomAttributeData(cad, attrType, out typeValue, allowTypeAlso, false, false);
                    } 
                }
 
                if (!attributeDataFound) 
                {
                    currentType = currentType.BaseType; // object.BaseType is null, used as terminating condition for the while() loop. 
                }
            }

            return attributeDataString; 
        }
 
        // Helper that inspects a specific CustomAttributeData obtained via ReflectionOnlyLoad, and 
        // returns its value if the Type of the attribiutes matches the passed in attrType. It only
        // looks for attributes with no values or a single value of Type string that is passed in via 
        // a ctor. If allowTypeAlso is true, then it looks for values of typeof(Type) as well in the
        // single value case. If noArgs == false and zeroArgsAllowed = true, that means 0 or 1 args
        // are permissible.
        private static string GetCustomAttributeData(CustomAttributeData cad, 
                                                     Type attrType,
                                                 out Type typeValue, 
                                                     bool allowTypeAlso, 
                                                     bool noArgs,
                                                     bool zeroArgsAllowed) 
        {
            string attrValue = null;
            typeValue = null;
 
            // get the Constructor info
            ConstructorInfo cinfo = cad.Constructor; 
            if (cinfo.ReflectedType == attrType) 
            {
                // typedConstructorArguments (the Attribute constructor arguments) 
                // [MyAttribute("test", Name=Hello)]
                // "test" is the Constructor Argument
                IList constructorArguments = cad.ConstructorArguments;
                if (constructorArguments.Count == 1 && !noArgs) 
                {
                    CustomAttributeTypedArgument tca = constructorArguments[0]; 
                    attrValue = tca.Value as String; 
                    if (attrValue == null && allowTypeAlso && tca.ArgumentType == typeof(Type))
                    { 
                        typeValue = tca.Value as Type;
                        attrValue = typeValue.AssemblyQualifiedName;
                    }
 
                    if (attrValue == null)
                    { 
                        throw new ArgumentException(SR.Get(SRID.ParserAttributeArgsLow, attrType.Name)); 
                    }
                } 
                else if (constructorArguments.Count == 0)
                {
                    // zeroArgsAllowed = true for CPA for example.
                    // CPA with no args is valid and would mean that this type is overriding a base CPA 
                    if (noArgs || zeroArgsAllowed)
                    { 
                        attrValue = string.Empty; 
                    }
                    else 
                    {
                        throw new ArgumentException(SR.Get(SRID.ParserAttributeArgsLow, attrType.Name));
                    }
                } 
                else
                { 
                    throw new ArgumentException(SR.Get(SRID.ParserAttributeArgsHigh, attrType.Name)); 
                }
            } 

            return attrValue;
        }
 
#endregion Attributes
 
#region Assembly Loading 
        //
        // Clean up the cache entry for the given assembly, so that it can be reloaded for the next build cycle. 
        // Usually it is called by MarkupCompiler task.
        //
        internal static void ResetCacheForAssembly(string assemblyName)
        { 
            string assemblyNameLookup = assemblyName.ToUpper(CultureInfo.InvariantCulture);
#if PBTCOMPILER 
            _reflectionOnlyLoadedAssembliesHash[assemblyNameLookup] = null; 
#else
            _loadedAssembliesHash[assemblyNameLookup] = null; 
#endif
        }

        internal static Assembly LoadAssembly(string assemblyName, string assemblyPath) 
        {
#if PBTCOMPILER 
            return ReflectionOnlyLoadAssembly(assemblyName, assemblyPath); 
#else
            return LoadAssemblyHelper(assemblyName, assemblyPath); 
#endif
        }

#if !PBTCOMPILER 
        internal static Assembly GetAlreadyLoadedAssembly(string assemblyNameLookup)
        { 
            return (Assembly)_loadedAssembliesHash[assemblyNameLookup]; 
        }
 
        // Loads the Assembly with the specified name at the specified optional location.
        //
        // assemblyName is either short name or full name.
        // assemblyPath is either full file path or null. 
        //
        private static Assembly LoadAssemblyHelper(string assemblyGivenName, string assemblyPath) 
        { 
            AssemblyName assemblyName = new AssemblyName(assemblyGivenName);
            string assemblyShortName = assemblyName.Name; 
            assemblyShortName = assemblyShortName.ToUpper(CultureInfo.InvariantCulture);

            // Check if the assembly has already been loaded.
            Assembly retassem = (Assembly)_loadedAssembliesHash[assemblyShortName]; 

            if (retassem != null) 
            { 
                if (assemblyName.Version != null)
                { 
                    AssemblyName cachedName = new AssemblyName(retassem.FullName);
                    if (!AssemblyName.ReferenceMatchesDefinition(assemblyName, cachedName))
                    {
                        string request = assemblyName.ToString(); 
                        string found = cachedName.ToString();
                        throw new InvalidOperationException(SR.Get(SRID.ParserAssemblyLoadVersionMismatch, request, found)); 
                    } 
                }
            } 
            else
            {
                // Check if the current AppDomain has this assembly loaded for some other reason.
                // If so, then just use that assembly and don't attempt to load another copy of it. 
                // Only do this if no path is provided.
                if (String.IsNullOrEmpty(assemblyPath)) 
                    retassem = SafeSecurityHelper.GetLoadedAssembly(assemblyGivenName, true /* ignoreCase */); 

                if (retassem == null) 
                {
                    if (!String.IsNullOrEmpty(assemblyPath))
                    {
 
                        // assemblyPath is set, Load the assembly from this specified place.
                        // the path must be full file path which contains directory, file name and extension. 
                        Debug.Assert(!assemblyPath.EndsWith("\\"), "the assembly path should be a full file path containing file extension"); 

                        // LoadFile will only override your request only if it is in the GAC 
                        retassem = Assembly.LoadFile(assemblyPath);
                    }
                    //
                    // At compile time, the build task should always pass the full path of the referenced assembly, even if it 
                    // comes from GAC. But below code snippet can run if parser wants to try loading an assembly w/o a path.
                    // This also makes run-time assembly load consistent with compile-time semantics. 
                    else 
                    {
                        try 
                        {
                            retassem = Assembly.Load(assemblyGivenName);
                        }
                        catch (System.IO.FileNotFoundException) 
                        {
                            // This may be a locally defined assembly that has not been created yet. 
                            // To support these cases, just set a null assembly and return.  This 
                            // will fail downstream if it really was an assembly miss.
                            retassem = null; 
                        }
                    }
                }
 
                // Cache the assembly
                if (retassem != null) 
                { 
                    _loadedAssembliesHash[assemblyShortName] = retassem;
                } 
            }

            return retassem;
        } 

        private static Hashtable _loadedAssembliesHash = new Hashtable(8); 
#else 
        // returns true is sourceAssembly declares LocalAssemblyName as a friend
        internal static bool IsFriendAssembly(Assembly sourceAssembly) 
        {
            bool isFriend = false;
            Type typeValue = null;
 
            string friendAssemblyName = string.Empty;
            IList list = CustomAttributeData.GetCustomAttributes(sourceAssembly); 
 
            for (int j = 0; j < list.Count; j++)
            { 
                friendAssemblyName = GetCustomAttributeData(list[j], typeof(InternalsVisibleToAttribute), out typeValue, false, false, false);
                if (friendAssemblyName != null && friendAssemblyName == LocalAssemblyName)
                {
                    isFriend = true; 
                    break;
                } 
            } 

            return isFriend; 
        }

        internal static bool IsInternalAllowedOnType(Type type)
        { 
            return ((LocalAssemblyName == type.Assembly.GetName().Name) || IsFriendAssembly(type.Assembly));
        } 
 
        // The local assembly that contains the baml.
        internal static string LocalAssemblyName 
        {
            get { return _localAssemblyName; }
            set { _localAssemblyName = value; }
        } 

        private static string _localAssemblyName = string.Empty; 
 
        internal static bool HasAlreadyReflectionOnlyLoaded(string assemblyNameLookup)
        { 
             //
             // If the cache contains an entry for the given assemblyname, and its value is not
             // null, it marks the assembly has been loaded.
             // 
             // Since ResetCacheForAssembly( ) just sets "null" in the hashtable for a given assembly
             // without really removing it, it is possible that an assembly is not reloaded before this 
             // method is called. 
             // Such as for the local-type-ref xaml file compilation,  the cache entry for the temporary
             // assembly is reset to null, but it is not reloaded for MCPass1. 
             //
             // We don't want to change the behavior of ResetCacheForAssembly( ) at this moment. (Resetting
             // the value to null without really removing the entry is helpful for the perf)
             // 

             return (_reflectionOnlyLoadedAssembliesHash.Contains(assemblyNameLookup) && _reflectionOnlyLoadedAssembliesHash[assemblyNameLookup] != null); 
        } 

        internal static Assembly GetAlreadyReflectionOnlyLoadedAssembly(string assemblyNameLookup) 
        {
             return (Assembly)_reflectionOnlyLoadedAssembliesHash[assemblyNameLookup];
        }
 
        //
        // For a given assembly name and its full path, Reflection-Only load the assembly directly 
        // from the file in disk or load the file to memory and then create assembly instance from 
        // memory buffer data.
        // 
        private static Assembly ReflectionOnlyLoadAssembly(string assemblyGivenName, string fullpath)
        {
            Debug.Assert(String.IsNullOrEmpty(assemblyGivenName) == false, "assemblyName should not be empty.");
 
            AssemblyName assemblyName = new AssemblyName(assemblyGivenName);
            string assemblyShortName = assemblyName.Name; 
            assemblyShortName = assemblyShortName.ToUpper(CultureInfo.InvariantCulture); 

            Assembly asm = (Assembly)_reflectionOnlyLoadedAssembliesHash[assemblyShortName]; 
            if (asm != null)
            {
                if (assemblyName.Version != null)
                { 
                    AssemblyName cachedName = new AssemblyName(asm.FullName);
                    if (!AssemblyName.ReferenceMatchesDefinition(assemblyName, cachedName)) 
                    { 
                        string request = assemblyName.ToString();
                        string found = cachedName.ToString(); 
                        throw new InvalidOperationException(SR.Get(SRID.ParserAssemblyLoadVersionMismatch, request, found));
                    }
                }
            } 
            // Reflection doesn't work with mscorlib (different mscorlib's that is).  We have problems if
            // the mscorlib is a dehydrated / asmMeta style reference assembly. 
            // Just use the real MsCorLib we are running on.  The alternative is failure. 
            else if ((String.Compare (assemblyShortName, "mscorlib", StringComparison.OrdinalIgnoreCase)==0))
            { 
                Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
                for(int i=0; i= 0; i--)
                           { 
                               if (String.Compare(assemblies[i].GetName().Name, assemblyGivenName, StringComparison.OrdinalIgnoreCase) == 0)
                               { 
                                   asm = assemblies[i]; 
                                   break;
                               } 
                           }
                        }
                    }
                } 
                else if (!String.IsNullOrEmpty(fullpath))
                { 
                    asm = Assembly.ReflectionOnlyLoadFrom(fullpath); 
                }
                else if (asm == null) 
                {
                    // In the compiler scenario this will be encountered only when there is no path
                    // and parser needs to call this directly to attempt to load an assembly.
                    try 
                    {
                         asm = Assembly.ReflectionOnlyLoad(assemblyGivenName); 
                    } 
                    catch (System.IO.FileNotFoundException)
                    { 
                        // This may be a locally defined assembly that has not been created yet.
                        // To support these cases, just set a null assembly and return.  This
                        // will fail downstream if it really was an assembly miss.
                        asm = null; 
                    }
                } 
 
                if (asm != null)
                { 
                    _reflectionOnlyLoadedAssembliesHash[assemblyShortName] = asm;
                }
            }
 
            return asm;
        } 
 
        private static Hashtable _reflectionOnlyLoadedAssembliesHash = new Hashtable(8);
 
        //
        // Copy assembly file from disk to memory, and return the memory buffer.
        //
        internal static byte[] GetAssemblyContent(string filepath) 
        {
            byte[] asmContents = null; 
 
            using (FileStream fileStream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.Read))
            { 
                // FileStream.Read does not support offsets or lengths
                // larger than int.MaxValue.
                if (fileStream.Length > int.MaxValue)
                { 
                    return null;
                } 
 
                int size = (int)fileStream.Length;
                asmContents = new byte[size]; 
                if (size > 0)
                {
                    ReliableRead(fileStream, asmContents, 0, size);
                } 

                // With using statement, fileStream can always be disposed, 
                // there is no need to put code here to explicitly dispose the 
                // file stream object.
            } 

            return asmContents;
        }
 
        //
        // set flag for the assembly to indicate that this assembly should be loaded from memory buffer 
        // instead of file in disk. 
        //
        // Usually it is called by MarkupCompiler task. 
        //
        internal static void SetContentLoadForAssembly(string assemblyName)
        {
            string assemblyNameLookup = assemblyName.ToUpper(CultureInfo.InvariantCulture); 
            _contentLoadAssembliesHash[assemblyNameLookup] = true;
        } 
 
        /// 
        /// Read utility that is guaranteed to return the number of bytes requested 
        /// if they are available.
        /// 
        /// stream to read from
        /// buffer to read into 
        /// offset in buffer to write to
        /// bytes to read 
        /// bytes read 
        /// Normal Stream.Read does not guarantee how many bytes it will
        /// return.  This one does. 
        private static int ReliableRead(Stream stream, byte[] buffer, int offset, int count)
        {
            /* Invariant.Assert is not available in PBT
            Invariant.Assert(stream != null); 
            Invariant.Assert(buffer != null);
            Invariant.Assert(buffer.Length > 0); 
            Invariant.Assert(offset >= 0); 
            Invariant.Assert(count >= 0);
            Invariant.Assert(checked(offset + count<= buffer.Length)); 
            */

            // let's read the whole block into our buffer
            int totalBytesRead = 0; 
            while (totalBytesRead < count)
            { 
                int bytesRead = stream.Read(buffer, 
                                offset + totalBytesRead,
                                count - totalBytesRead); 
                if (bytesRead == 0)
                {
                    break;
                } 
                totalBytesRead += bytesRead;
            } 
            return totalBytesRead; 
        }
 
        private static Hashtable _contentLoadAssembliesHash = new Hashtable(1);
#endif

#endregion Assembly Loading 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

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