Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Some Time on Reflection

0.00/5 (No votes)
27 Aug 2010 1  
An article that explains some valuable aspects about .NET's Reflection API

Introduction

The article will focus on the .NET Framework’s Reflection API. Reflection documentation often includes attributes and writing dynamic code, but I will avoid the latter and try to explain some of the more important aspects of using Reflection, even though it might not appear to have any value in writing real-world applications. On the contrary, it does and the one who gets proficient at it will be able to use Reflection to write development tools, or even programs that reduce heap consumption. For the important sake of the beginner, certain sections will step though some source code in order to get a grasp on C# syntax, but the article (in my limited knowledge) probably nears the intermediate. Reflection is frequently used to determine what types an assembly defines. The Framework Class Library provides many methods to get this information, yet the most commonly used method is Assembly's GetExportedTypes. Below is just some sample source code that loads an assembly and shows the names of all of the publicly exported types defined in it. The output will appear in the following section after some basics are explained. Examine this code, and then we will take a look at the Assembly class' methods, properties, and static methods.

using System;
using System.Reflection;
public static class Program {
public static void Main() {
String dataAssembly = "System.Data, version=4.0.0.0, " +
"culture=neutral, PublicKeyToken=b77a5c561934e089";
LoadAssemAndShowPublicTypes(dataAssembly);     
}
    
private static void LoadAssemAndShowPublicTypes(String assemId) {   
    Assembly a = Assembly.Load(assemId);   
foreach (Type t in a.GetExportedTypes()) {
Console.WriteLine(t.FullName);
             }
        }
} 

The Assembly Class Static Methods

  • GetAssembly
  • GetCallingAssembly
  • GetEntryAssembly
  • GetExecutingAssembly
  • Load
  • LoadFile
  • LoadFrom
  • ReflectionOnlyLoad
  • ReflectionOnlyLoadFrom

As you can see, the GetExportedTypes method is not static. Examine the Assembly class’s properties:

  • EntryPoint
  • FullName
  • GlobalAssemblyCache
  • Location
  • ReflectionOnly

At this point, it is important to examine the syntax. Examine this program:

using System;
using System.Reflection;
class Program {
static void Main(string[]  area)
{
   string path = @"C:\windows\Microsoft.net\Framework\v2.0.50727\System.dll";
   Assembly a = Assembly.LoadFile(path);
   ShowAssemblyInfo(a);
   Assembly ourAssembly = Assembly.GetExecutingAssembly();
   ShowAssemblyInfo(ourAssembly);
   Console.Read();
   }
   static void ShowAssemblyInfo(Assembly a)
   {
      Console.WriteLine(a.FullName);
      Console.WriteLine("From GAC? {0}", a.GlobalAssemblyCache);
      Console.WriteLine("Path:     {0}", a.Location);
      Console.WriteLine("Version:  {0}", a.ImageRuntimeVersion);

      foreach (Module m in a.GetModules())
      {
          Console.WriteLine("   Mod: {0}", m.Name);
      }

      Console.WriteLine();
    }
  } 

Here is the output:

c:\Windows\Microsoft.NET\Framework\v4.0.30319>getmod
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
From GAC? True
Path:     C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c
561934e089\System.dll
Version:  v4.0.30319
   Mod: System.dll

GetMod, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
From GAC? False
Path:     c:\Windows\Microsoft.NET\Framework\v4.0.30319\GetMod.exe
Version:  v4.0.30319
   Mod: GetMod.exe     

The code first declares a string:

string path = @"C:\windows\Microsoft.net\Framework\v2.0.50727\System.dll";

The quoted string is stored in the value assigned to the string object; “path”, therefore holds the reference to directory path that is contained in the quotes on the left (which contains the assembly to be loaded). The next line of code instantiates the Assembly class. This is set equal to the Assembly class’ static method LoadFile. Notice that this method has the above path (which stores the value of the string) value passed as a parameter. Note also that the “a” following Assembly now stores that path of the assembly since it has now been loaded:

Assembly a = Assembly.LoadFile(path); 

At this point, we write a static method to display the information about the currently loaded assembly. As it is now executing, we instantiate another instance of the Assembly class. The static method ShowAssemblyInfo does what its name implies. It is important for the beginner to notice that the original value “a” that functioned as a reference for the path of the string that was passed as a parameter is written with dot syntax to display the properties: (a.Location, a.GlobalAssemblyCache, a.FullName, and so forth.) Below are some of the Assembly class’ methods that aren’t static:

  • CreateInstance
  • GetCustomAttributes
  • GetExportedTypes
  • GetModule
  • GetModules
  • GetTypes

Having said that, let’s a look at the output of the original source code. For the sake of brevity, note that these are (nearly half of) the public exported types:

System.Text.RegularExpressions.Regex
System.Text.RegularExpressions.MatchEvaluator
System.Text.RegularExpressions.Capture
System.Text.RegularExpressions.CaptureCollection
System.Text.RegularExpressions.RegexCompilationInfo
System.Text.RegularExpressions.Group
System.Text.RegularExpressions.GroupCollection
System.Text.RegularExpressions.RegexRunner
System.Text.RegularExpressions.Match
System.Text.RegularExpressions.MatchCollection
System.Text.RegularExpressions.RegexOptions
System.Text.RegularExpressions.RegexRunnerFactory
System.CodeDom.CodeObject
System.CodeDom.CodeExpression
System.CodeDom.CodeArgumentReferenceExpression
System.CodeDom.CodeArrayCreateExpression
System.CodeDom.CodeArrayIndexerExpression
System.CodeDom.CodeStatement
System.CodeDom.CodeAssignStatement
System.CodeDom.CodeAttachEventStatement
System.CodeDom.CodeAttributeArgument
System.CodeDom.CodeAttributeArgumentCollection
System.CodeDom.CodeAttributeDeclaration
System.CodeDom.CodeAttributeDeclarationCollection
System.CodeDom.CodeBaseReferenceExpression
System.CodeDom.CodeBinaryOperatorExpression
System.CodeDom.CodeBinaryOperatorType
System.CodeDom.CodeCastExpression
System.CodeDom.CodeCatchClause
System.CodeDom.CodeCatchClauseCollection
System.CodeDom.CodeDirective
System.CodeDom.CodeChecksumPragma
System.CodeDom.CodeComment
System.CodeDom.CodeCommentStatement
System.CodeDom.CodeCommentStatementCollection
System.CodeDom.CodeCompileUnit
System.CodeDom.CodeConditionStatement
System.CodeDom.CodeTypeMember
System.CodeDom.CodeMemberMethod
System.CodeDom.CodeConstructor
System.CodeDom.CodeDefaultValueExpression
System.CodeDom.CodeDelegateCreateExpression
System.CodeDom.CodeDelegateInvokeExpression
System.CodeDom.CodeDirectionExpression
System.CodeDom.CodeDirectiveCollection
System.CodeDom.CodeEntryPointMethod
System.CodeDom.CodeEventReferenceExpression
System.CodeDom.CodeExpressionCollection
System.CodeDom.CodeExpressionStatement
System.CodeDom.CodeFieldReferenceExpression
System.CodeDom.CodeGotoStatement
System.CodeDom.CodeIndexerExpression
System.CodeDom.CodeIterationStatement
System.CodeDom.CodeLabeledStatement
System.CodeDom.CodeLinePragma
System.CodeDom.CodeMemberEvent
System.CodeDom.CodeMemberField
System.Net.FileWebResponse
System.Net.FtpStatusCode
……… etc ………………
System.Net.NetworkInformation.NetworkInterface
System.Net.NetworkInformation.NetworkInterfaceComponent
System.Net.NetworkInformation.NetBiosNodeType
System.Net.NetworkInformation.OperationalStatus
System.Net.NetworkInformation.PhysicalAddress
System.Net.NetworkInformation.PingCompletedEventHandler
System.Net.NetworkInformation.PingCompletedEventArgs
System.Net.NetworkInformation.Ping
System.Net.NetworkInformation.PingException
System.Net.NetworkInformation.PingOptions
System.Net.NetworkInformation.PingReply
System.Net.NetworkInformation.PrefixOrigin
System.Net.NetworkInformation.SuffixOrigin
System.Net.NetworkInformation.TcpConnectionInformation
System.Net.NetworkInformation.TcpStatistics
System.Net.NetworkInformation.UdpStatistics
System.Net.NetworkInformation.TcpState
System.Net.Configuration.AuthenticationModuleElement
System.Net.Configuration.AuthenticationModuleElementCollection
System.Net.Configuration.AuthenticationModulesSection
System.Net.Configuration.BypassElement
System.Net.Configuration.BypassElementCollection
System.Net.Configuration.ConnectionManagementElement
System.Net.Configuration.ConnectionManagementElementCollection
System.Net.Configuration.ConnectionManagementSection
System.Net.Configuration.DefaultProxySection
System.Net.Configuration.HttpWebRequestElement
System.Net.Configuration.HttpListenerElement
System.Net.Configuration.HttpCachePolicyElement
System.Net.Configuration.FtpCachePolicyElement
System.Net.Configuration.Ipv6Element
System.Net.Configuration.MailSettingsSectionGroup
System.Net.Configuration.ModuleElement
System.Net.Configuration.NetSectionGroup
System.Net.Configuration.PerformanceCountersElement
System.Net.Configuration.ProxyElement
System.Net.Configuration.ProxyElement+BypassOnLocalValues
System.Net.Configuration.ProxyElement+UseSystemDefaultValues
System.Net.Configuration.ProxyElement+AutoDetectValues
System.Net.Configuration.RequestCachingSection
System.Configuration.SchemeSettingElement
System.Configuration.SchemeSettingElementCollection
System.Net.Configuration.SettingsSection
System.Net.Configuration.ServicePointManagerElement
System.Net.Configuration.SmtpSection
System.Net.Configuration.SmtpNetworkElement
System.Net.Configuration.SmtpSpecifiedPickupDirectoryElement
System.Net.Configuration.SocketElement
…..etc….
System.Diagnostics.FileVersionInfo
System.Diagnostics.ICollectData
System.Diagnostics.InstanceData
System.Diagnostics.InstanceDataCollection
System.Diagnostics.InstanceDataCollectionCollection
System.Diagnostics.MonitoringDescriptionAttribute
System.Diagnostics.OverflowAction
System.Diagnostics.PerformanceCounter
System.Diagnostics.PerformanceCounterCategory
System.Diagnostics.PerformanceCounterCategoryType
System.Diagnostics.PerformanceCounterInstanceLifetime
System.Diagnostics.PerformanceCounterManager
System.Diagnostics.PerformanceCounterPermission
System.Diagnostics.PerformanceCounterPermissionAccess
System.Diagnostics.PerformanceCounterPermissionAttribute
System.Diagnostics.PerformanceCounterPermissionEntry
System.Diagnostics.PerformanceCounterPermissionEntryCollection
System.Diagnostics.PerformanceCounterType
System.Diagnostics.Process
System.Diagnostics.ProcessModule
System.Diagnostics.ProcessModuleCollection
System.Diagnostics.ProcessPriorityClass
System.Diagnostics.ProcessStartInfo
System.Diagnostics.ProcessThread
System.Diagnostics.ProcessThreadCollection
System.Diagnostics.ProcessWindowStyle
System.Diagnostics.Stopwatch
System.Diagnostics.ThreadPriorityLevel
System.Diagnostics.ThreadState
System.Diagnostics.ThreadWaitReason
System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute
System.Configuration.AppSettingsReader
System.IO.Ports.Handshake
System.IO.Ports.Parity
System.IO.Ports.SerialError
System.IO.Ports.SerialErrorReceivedEventArgs
System.IO.Ports.SerialErrorReceivedEventHandler
System.IO.Ports.SerialPinChange
System.IO.Ports.SerialPinChangedEventArgs
System.IO.Ports.SerialPinChangedEventHandler
System.IO.Ports.SerialPort
System.IO.Ports.SerialData
System.IO.Ports.SerialDataReceivedEventArgs
System.IO.Ports.SerialDataReceivedEventHandler
System.IO.Ports.StopBits   

What Type is that Object?

Or, what is a Type Object? As we well know, all objects in .NET derive from System.Object. One the methods defined in that root namespace is GetType. Notice that the previous code iterates over an array of System.Type objects. The System.Type type is your starting point for doing type and object manipulations. System.Type is an abstract base type derived from System.Reflection.MemberInfo (because a Type can be a member of another type). The FCL provides a few types that are derived from System.Type:System.RuntimeType,  System.ReflectionOnlyType, System.Reflection.TypeDelegator, and some types defined in the System.Reflection. Emit namespace (EnumBuilder, GenericTypeParameterBuilder, and TypeBuilder). The Object class-supported method GetType returns a Type object that refers to the actual Type of an object. For example, let’s create an Animal class and then create two classes that derive from that Animal class:

using System;
public class Animal
   {
   }
public class Dog : Animal
   {
   }
public class Cat : Animal
   {
   }
class App {
static void Main() {
Animal aAnim = new Animal();
Animal aDog = new Dog();
Animal aCat = new Cat();
Console.WriteLine("Typename for aAnim is {0}", aAnim.GetType().Name);
Console.WriteLine("Typename for aDog is {0}", aDog.GetType().Name);
Console.WriteLine("Typename for aCat is  {0}", aCat.GetType().Name);
 }
}   

The output is as expected. Notice the use of the “typeof” keyword:

Typename for aAnim is Animal
Typename for aDog   is Dog
Typename for aCat   is  Cat  

To construct an instance for a generic type, first get a reference to the open type, and then call Type’s public instance MakeGenericType method, passing in an array of types that you want to use as the type arguments. Then, take the returned Type object and pass it into one of the various methods listed above. Here is an example:

using System; 
using System.Reflection; 
using System.Collections.Generic; 
using System.Linq; 
internal sealed class Dictionary { } 
public static class Program { 
public static void Main() 
{ 
Type openType = typeof(Dictionary<,>); 
Type closedType = openType.MakeGenericType(typeof(String), 
	typeof(Int32)); Object o = Activator.CreateInstance(closedType); 
Console.WriteLine(o.GetType()); 
} 
}  

When you compile this code, you should get the following result:

Dictionary`2[System.String,System.Int32]    

Using Reflection to Discover a Type’s Members

According to Microsoft’s technical documentation, the ability to discover and invoke a type’s members is typically used to create developer tools and utilities that analyze an assembly by looking for certain programming patterns or uses of certain members. Examples of tools/utilities that do this are ILDasm.exe, FxCopCmd.exe, and Visual Studio’s Windows Forms and Web Designers.

Fields, constructors, methods, properties, events, and nested types can all be defined as members within a type. The FCL contains a type called System.Reflection.MemberInfo. This class is an abstract base class that encapsulates a bunch of properties common to all type members. Derived from MemberInfo are a bunch of classes; each class encapsulates some more properties related to a specific type member. Below is a hierarchal listing of these types:

System.Object
System.Reflection.MemberInfo
System.Type
System.Reflection.FieldInfo
System.Reflection.MethodBase
System.Reflection.ContructorInfo
System.Reflection.MethodInfo
System.Reflection.PropertyInfo
System.Reflection.EventInfo    

For each type, the GetMembers method is called and returns an array of MemberInfo-derived objects; each object refers to a single member defined within the type. The BindingFlags variable, bf, passed to the GetMembers method tells the method which kinds of members to return. Then, for each member, its kind (field, constructor, method, property, etc.) and its string value (obtained by calling ToString) is shown. The topic of BindingFlags will be discussed shortly. Study this code:

using System;
using System.Reflection;
public static class Program {
public static void Main() {
// Loop through all assemblies loaded in this AppDomain
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly a in assemblies) {
WriteLine(0, "Assembly: {0}", a);
// Find Types in the assembly
foreach (Type t in a.GetExportedTypes()) {
WriteLine(1, "Type: {0}", t);
// Discover the type's members
const BindingFlags bf = BindingFlags.DeclaredOnly |
BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance | BindingFlags.Static;
foreach (MemberInfo mi in t.GetMembers(bf)) {
String typeName = String.Empty;
if (mi is Type) typeName = "(Nested) Type";
else if (mi is FieldInfo) typeName = "FieldInfo";
else if (mi is MethodInfo) typeName = "MethodInfo";
else if (mi is ConstructorInfo) typeName = "ConstructoInfo";
else if (mi is PropertyInfo) typeName = "PropertyInfo";
else if (mi is EventInfo) typeName = "EventInfo";
WriteLine(2, "{0}: {1}", typeName, mi);
    }
  }
 }
}
 private static void WriteLine(Int32 indent, String format, params Object[] args) {
Console.WriteLine(new String(' ', 3 * indent) + format, args);
  }
}

An enormous amount of information is outputted when the compiled code is run. Here is a small sampling of the output, and try to make a connection to the hierarchal list.

Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
   Type: System.Object
      MethodInfo: System.String ToString()
      MethodInfo: Boolean Equals(System.Object)
      MethodInfo: Boolean Equals(System.Object, System.Object)
      MethodInfo: Boolean ReferenceEquals(System.Object, System.Object)
      MethodInfo: Int32 GetHashCode()
      MethodInfo: System.Type GetType()
      MethodInfo: Void Finalize()
      MethodInfo: System.Object MemberwiseClone()
      MethodInfo: Void FieldSetter(System.String, System.String, System.Object)
      MethodInfo: Void FieldGetter(System.String, System.String, System.Object ByRef)
      MethodInfo: System.Reflection.FieldInfo GetFieldInfo(System.String, System.String)
      ConstructoInfo: Void .ctor()
   Type: System.Runtime.Serialization.ISerializable
      MethodInfo: Void GetObjectData(System.Runtime.Serialization.SerializationInfo, 
	System.Runtime.Serialization.StreamingContext)
   Type: System.Runtime.InteropServices._Exception
      MethodInfo: System.String ToString()
      MethodInfo: Boolean Equals(System.Object)
      MethodInfo: Int32 GetHashCode()
      MethodInfo: System.Type GetType()
      MethodInfo: System.String get_Message()
      MethodInfo: System.Exception GetBaseException()
      MethodInfo: System.String get_StackTrace()
      MethodInfo: System.String get_HelpLink()
      MethodInfo: Void set_HelpLink(System.String)
      MethodInfo: System.String get_Source()
      MethodInfo: Void set_Source(System.String)
      MethodInfo: Void GetObjectData(System.Runtime.Serialization.SerializationInfo, 
	System.Runtime.Serialization.StreamingContext)
      MethodInfo: System.Exception get_InnerException()
      MethodInfo: System.Reflection.MethodBase get_TargetSite()
      PropertyInfo: System.String Message
      PropertyInfo: System.String StackTrace
      PropertyInfo: System.String HelpLink
      PropertyInfo: System.String Source
      PropertyInfo: System.Exception InnerException
      PropertyInfo: System.Reflection.MethodBase TargetSite
   Type: System.Exception
      MethodInfo: System.String get_Message()
      MethodInfo: System.Collections.IDictionary get_Data()
      MethodInfo: System.Exception GetBaseException()
      MethodInfo: System.Exception get_InnerException()
      MethodInfo: System.Reflection.MethodBase get_TargetSite()
      MethodInfo: System.Reflection.MethodBase GetTargetSiteInternal()
      MethodInfo: System.String get_StackTrace()
      MethodInfo: System.String GetStackTrace(Boolean)
      MethodInfo: Void SetErrorCode(Int32)
      MethodInfo: System.String get_HelpLink()
      MethodInfo: Void set_HelpLink(System.String)
      MethodInfo: System.String get_Source()
      MethodInfo: Void set_Source(System.String)
      MethodInfo: System.String ToString()
      MethodInfo: System.String ToString(Boolean)
      MethodInfo: Void add_SerializeObjectState
	(System.EventHandler`1[System.Runtime.Serialization.SafeSerializationEventArgs])
      MethodInfo: Void remove_SerializeObjectState
	(System.EventHandler`1[System.Runtime.Serialization.SafeSerializationEventArgs])
      MethodInfo: Void GetObjectData
	(System.Runtime.Serialization.SerializationInfo, 
	System.Runtime.Serialization.StreamingContext)
      MethodInfo: System.Exception PrepForRemoting()
      MethodInfo: Void InternalPreserveStackTrace()
      MethodInfo: Int32 get_HResult()
      MethodInfo: Void set_HResult(Int32)
      MethodInfo: System.String InternalToString()
      MethodInfo: System.Type GetType()
      MethodInfo: Boolean get_IsTransient()
      MethodInfo: System.String GetMessageFromNativeResources(ExceptionMessageKind)
      MethodInfo: Void Init()
      MethodInfo: Boolean IsImmutableAgileException(System.Exception)
      MethodInfo: System.String GetClassName()
      MethodInfo: System.IRuntimeMethodInfo GetMethodFromStackTrace(System.Object)
      MethodInfo: System.Reflection.MethodBase GetExceptionMethodFromStackTrace()
      MethodInfo: System.String GetExceptionMethodString()
      MethodInfo: System.Reflection.MethodBase GetExceptionMethodFromString()
      MethodInfo: Void OnDeserialized(System.Runtime.Serialization.StreamingContext)
      MethodInfo: Boolean nIsTransient(Int32)
      MethodInfo: Void GetMessageFromNativeResources
	(ExceptionMessageKind, System.Runtime.CompilerServices.StringHandleOnStack)
      ConstructoInfo: Void .ctor()
      ConstructoInfo: Void .ctor(System.String)
      ConstructoInfo: Void .ctor(System.String, System.Exception)
      ConstructoInfo: Void .ctor
	(System.Runtime.Serialization.SerializationInfo, 
	System.Runtime.Serialization.StreamingContext)
      PropertyInfo: System.String Message
      PropertyInfo: System.Collections.IDictionary Data
      PropertyInfo: System.Exception InnerException
      PropertyInfo: System.Reflection.MethodBase TargetSite
      PropertyInfo: System.String StackTrace
      PropertyInfo: System.String HelpLink
      PropertyInfo: System.String Source
      PropertyInfo: Int32 HResult
      PropertyInfo: Boolean IsTransient
      EventInfo: System.EventHandler`1
	[System.Runtime.Serialization.SafeSerializationEventArgs] SerializeObjectState
      FieldInfo: System.String _className
      FieldInfo: System.Reflection.MethodBase _exceptionMethod
      FieldInfo: System.String _exceptionMethodString
      FieldInfo: System.String _message
      FieldInfo: System.Collections.IDictionary _data
      FieldInfo: System.Exception _innerException
      FieldInfo: System.String _helpURL
      FieldInfo: System.Object _stackTrace
      FieldInfo: System.Object _watsonBuckets
      FieldInfo: System.String _stackTraceString
      FieldInfo: System.String _remoteStackTraceString
      FieldInfo: Int32 _remoteStackIndex
      FieldInfo: System.Object _dynamicMethods
      FieldInfo: Int32 _HResult
      FieldInfo: System.String _source
      FieldInfo: IntPtr _xptrs
      FieldInfo: Int32 _xcode
      FieldInfo: UIntPtr _ipForWatsonBuckets
      FieldInfo: System.Runtime.Serialization.SafeSerializationManager 
		_safeSerializationManager
      FieldInfo: Int32 _COMPlusExceptionCode
      (Nested) Type: System.Exception+ExceptionMessageKind
   Type: System.ValueType
      MethodInfo: Boolean Equals(System.Object)
      MethodInfo: Int32 GetHashCode()
      MethodInfo: Int32 GetHashCodeOfPtr(IntPtr)
      MethodInfo: System.String ToString()
      MethodInfo: Boolean CanCompareBits(System.Object)
      MethodInfo: Boolean FastEqualsCheck(System.Object, System.Object)
      ConstructoInfo: Void .ctor()       

Using the BindingFlags

The BindingFlags enumeration is used to control how members of a type are retrieved using the GetMembers method, as well as the specific members for each member type. More to the point, BindingFlags filter the kinds of members that are returned. You query a type’s members by calling Type’s GetMembers, GetNestedTypes, GetFields, GetConstructors, GetMethods, GetProperties, or GetEvents methods. When you call any of these methods, you can pass in an instance of a System.Reflection.BindingFlags enumerated type. The enumerated type identifies a set of bit flags OR’d together to help you filter the members that are returned from these methods. Despite the fact that we use BindingFlags is our last example, here is the source code that exemplifies its straight purpose:

using System;
using System.Reflection;
public class Program
 {
    public static void Main(string[]  args)
    {
      string path = @"C:\Windows\Microsoft.NET\Framework\v2.0.50727\" +
      "System.ServiceProcess.dll";

       // using BindingFlags to only get the declared
       // and instance members

       BindingFlags flags =
       BindingFlags.DeclaredOnly |
       BindingFlags.Public |
       BindingFlags.Instance;

       Assembly a = Assembly.LoadFrom(path);
       Console.WriteLine(a.FullName);

       Type[] types = a.GetTypes();

       foreach ( Type t in types )
       {
         Console.WriteLine("  Type:  {0}", t.Name);
         MemberInfo[] m = t.GetMembers(flags);

       foreach (MemberInfo member in m)
        {
           Console.WriteLine("  {0}: {1}", member.MemberType, member.Name);
        }
       }

       Console.Read();
     }
  }  

When we run the compiled code, we will see that (as usual, there is an enormous amount of information) that .NET does use APIs to return info types that accept a BindingFlags flag-style enumeration value to constrain searches to those abstractions that hold certain properties:

System.ServiceProcess, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
  Type:  NativeMethods
  NestedType: SERVICE_STATUS
  NestedType: ServiceMainCallback
  NestedType: ServiceControlCallback
  NestedType: ServiceControlCallbackEx
  NestedType: StructFormat
  NestedType: ENUM_SERVICE_STATUS
  NestedType: ENUM_SERVICE_STATUS_PROCESS
  NestedType: QUERY_SERVICE_CONFIG
  NestedType: SERVICE_TABLE_ENTRY
  NestedType: LSA_UNICODE_STRING
  NestedType: LSA_UNICODE_STRING_withPointer
  NestedType: LSA_OBJECT_ATTRIBUTES
  NestedType: SERVICE_DESCRIPTION
  NestedType: SERVICE_DELAYED_AUTOSTART_INFO
  NestedType: SERVICE_FAILURE_ACTIONS
  NestedType: SC_ACTION
  NestedType: WTSSESSION_NOTIFICATION
  Type:  SERVICE_STATUS
  Field: serviceType
  Field: currentState
  Field: controlsAccepted
  Field: win32ExitCode
  Field: serviceSpecificExitCode
  Field: checkPoint
  Field: waitHint
  Type:  ServiceMainCallback
  Method: Invoke
  Method: BeginInvoke
  Method: EndInvoke
  Constructor: .ctor
  Type:  ServiceControlCallback
  Method: Invoke
  Method: BeginInvoke
  Method: EndInvoke
  Constructor: .ctor
  Type:  ServiceControlCallbackEx
  Method: Invoke
  Method: BeginInvoke
  Method: EndInvoke
  Constructor: .ctor
  Type:  PowerBroadcastStatus
  Field: value__
  Type:  SafeNativeMethods
  Type:  ServiceAccount
  Field: value__
  Type:  ServiceBase
  Method: RequestAdditionalTime
  Method: get_AutoLog
  Method: set_AutoLog
  Method: get_ExitCode
  Method: set_ExitCode
  Method: get_CanHandlePowerEvent
  Method: set_CanHandlePowerEvent
  Method: get_CanHandleSessionChangeEvent
  Method: set_CanHandleSessionChangeEvent
  Method: get_CanPauseAndContinue
  Method: set_CanPauseAndContinue
  Method: get_CanShutdown
  Method: set_CanShutdown
  Method: get_CanStop
  Method: set_CanStop
  Method: get_EventLog
  Method: get_ServiceName
  Method: set_ServiceName
  Method: Stop
  Method: ServiceMainCallback
  Constructor: .ctor
  Property: AutoLog
  Property: ExitCode
  Property: CanHandlePowerEvent
  Property: CanHandleSessionChangeEvent
  Property: CanPauseAndContinue
  Property: CanShutdown
  Property: CanStop
  Property: EventLog
  Property: ServiceName
  Type:  ServiceController
  Method: get_CanPauseAndContinue
  Method: get_CanShutdown
  Method: get_CanStop
  Method: get_DisplayName
  Method: set_DisplayName
  Method: get_DependentServices
  Method: get_MachineName
  Method: set_MachineName
  Method: get_ServiceName
  Method: set_ServiceName
  Method: get_ServicesDependedOn
  Method: get_ServiceHandle
  Method: get_Status
  Method: get_ServiceType
  Method: Close
  Method: Pause
  Method: Continue
  Method: ExecuteCommand
  Method: Refresh
  Method: Start
  Method: Start
  Method: Stop
  Method: WaitForStatus
  Method: WaitForStatus
  Constructor: .ctor
  Constructor: .ctor
  Constructor: .ctor
  Property: CanPauseAndContinue
  Property: CanShutdown
  Property: CanStop
  Property: DisplayName
  Property: DependentServices
  Property: MachineName
  Property: ServiceName
  Property: ServicesDependedOn
  Property: ServiceHandle
  Property: Status
  Property: ServiceType
  Type:  ServiceControllerPermission
  Method: get_PermissionEntries
  Constructor: .ctor
  Constructor: .ctor
  Constructor: .ctor
  Constructor: .ctor
  Property: PermissionEntries
  Type:  ServiceControllerPermissionAccess
  Field: value__
  Type:  ServiceControllerPermissionAttribute
  Method: get_MachineName
  Method: set_MachineName
  Method: get_PermissionAccess
  Method: set_PermissionAccess
  Method: get_ServiceName
  Method: set_ServiceName
  Method: CreatePermission
  Constructor: .ctor
  Property: MachineName
  Property: PermissionAccess
  Property: ServiceName
  Type:  ServiceControllerPermissionEntry
  Method: get_MachineName
  Method: get_PermissionAccess
  Method: get_ServiceName
  Constructor: .ctor
  Constructor: .ctor
  Property: MachineName
  Property: PermissionAccess
  Property: ServiceName
  Type:  ServiceControllerPermissionEntryCollection
  Method: get_Item
  Method: set_Item
  Method: Add
  Method: AddRange
  Method: AddRange
  Method: Contains
  Method: CopyTo
  Method: IndexOf
  Method: Insert
  Method: Remove
  Property: Item
  Type:  ServiceControllerStatus
  Field: value__
  Type:  ServiceInstaller
  Method: get_DisplayName
  Method: set_DisplayName
  Method: get_Description
  Method: set_Description
  Method: get_ServicesDependedOn
  Method: set_ServicesDependedOn
  Method: get_ServiceName
  Method: set_ServiceName
  Method: get_StartType
  Method: set_StartType
  Method: get_DelayedAutoStart
  Method: set_DelayedAutoStart
  Method: CopyFromComponent
  Method: Install
  Method: IsEquivalentInstaller
  Method: Rollback
  Method: Uninstall
  Constructor: .ctor
  Property: DisplayName
  Property: Description
  Property: ServicesDependedOn
  Property: ServiceName
  Property: StartType
  Property: DelayedAutoStart
  Type:  ServiceProcessDescriptionAttribute
  Method: get_Description
  Constructor: .ctor
  Property: Description
  Type:  ServiceProcessInstaller
  Method: get_HelpText
  Method: get_Password
  Method: set_Password
  Method: get_Account
  Method: set_Account
  Method: get_Username
  Method: set_Username
  Method: CopyFromComponent
  Method: Install
  Method: Rollback
  Constructor: .ctor
  Property: HelpText
  Property: Password
  Property: Account
  Property: Username
  Type:  ServiceStartMode
  Field: value__
  Type:  ServiceType
  Field: value__
  Type:  SessionChangeReason
  Field: value__
  Type:  SessionChangeDescription
  Method: get_Reason
  Method: get_SessionId
  Method: Equals
  Method: GetHashCode
  Method: Equals
  Property: Reason
  Property: SessionId
  Type:  TimeoutException
  Constructor: .ctor
  Constructor: .ctor
  Constructor: .ctor
  Type:  ServiceInstallerDialogResult
  Field: value__
  Type:  ServiceInstallerDialog
  Method: get_Password
  Method: set_Password
  Method: get_Result
  Method: get_Username
  Method: set_Username
  Constructor: .ctor
  Property: Password
  Property: Result
  Property: Username
  Type:  FXAssembly
  Type:  ThisAssembly
  Type:  AssemblyRef
  Type:  ResDescriptionAttribute
  Method: get_Description
  Constructor: .ctor
  Property: Description
  Type:  ResCategoryAttribute
  Constructor: .ctor
  Type:  Res
  Type:  ExternDll
  Type:  HResults
  Type:  StructFormat
  Field: value__
  Type:  ENUM_SERVICE_STATUS
  Constructor: .ctor
  Field: serviceName
  Field: displayName
  Field: serviceType
  Field: currentState
  Field: controlsAccepted
  Field: win32ExitCode
  Field: serviceSpecificExitCode
  Field: checkPoint
  Field: waitHint
  Type:  ENUM_SERVICE_STATUS_PROCESS
  Constructor: .ctor
  Field: serviceName
  Field: displayName
  Field: serviceType
  Field: currentState
  Field: controlsAccepted
  Field: win32ExitCode
  Field: serviceSpecificExitCode
  Field: checkPoint
  Field: waitHint
  Field: processID
  Field: serviceFlags
  Type:  QUERY_SERVICE_CONFIG
  Constructor: .ctor
  Field: dwServiceType
  Field: dwStartType
  Field: dwErrorControl
  Field: lpBinaryPathName
  Field: lpLoadOrderGroup
  Field: dwTagId
  Field: lpDependencies
  Field: lpServiceStartName
  Field: lpDisplayName
  Type:  SERVICE_TABLE_ENTRY
  Constructor: .ctor
  Field: name
  Field: callback
  Type:  LSA_UNICODE_STRING
  Constructor: .ctor
  Field: length
  Field: maximumLength
  Field: buffer
  Type:  LSA_UNICODE_STRING_withPointer
  Constructor: .ctor
  Field: length
  Field: maximumLength
  Field: pwstr
  Type:  LSA_OBJECT_ATTRIBUTES
  Constructor: .ctor
  Field: length
  Field: rootDirectory
  Field: pointerLsaString
  Field: attributes
  Field: pointerSecurityDescriptor
  Field: pointerSecurityQualityOfService
  Type:  SERVICE_DESCRIPTION
  Field: description
  Type:  SERVICE_DELAYED_AUTOSTART_INFO
  Field: fDelayedAutostart
  Type:  SERVICE_FAILURE_ACTIONS
  Field: dwResetPeriod
  Field: rebootMsg
  Field: command
  Field: numActions
  Field: actions
  Type:  SC_ACTION
  Field: type
  Field: delay
  Type:  WTSSESSION_NOTIFICATION
  Constructor: .ctor
  Field: size
  Field: sessionId
  Type:  SafeServiceHandle
  Type:  DeferredHandlerDelegate
  Method: Invoke
  Method: BeginInvoke
  Method: EndInvoke
  Constructor: .ctor
  Type:  DeferredHandlerDelegateCommand
  Method: Invoke
  Method: BeginInvoke
  Method: EndInvoke
  Constructor: .ctor
  Type:  DeferredHandlerDelegateAdvanced
  Method: Invoke
  Method: BeginInvoke
  Method: EndInvoke
  Constructor: .ctor
  Type:  UnsafeNativeMethods
  Type:  ServiceNameConverter
  Method: CanConvertFrom
  Method: ConvertFrom
  Method: GetStandardValues
  Method: GetStandardValuesExclusive
  Method: GetStandardValuesSupported
  Constructor: .ctor       

In conclusion, recall that the C# compiler emits metadata and IL code. The metadata is stored in a bunch of tables. When you build an assembly or a module, the compiler that you are using creates a type definition table, a field definition table, a method definition table, and so on. The System.Reflection namespace contains several types that allow you to write code that reflects over (or parses) these metadata tables. In effect, the types in this namespace offer an object model over the metadata contained in an assembly or a module. Using these object model types, you can easily enumerate all of the types in a type definition metadata table. Then for each type, you can obtain its base type, the interfaces it implements, and the flags that are associated with the type. Additional types in the System.Reflection namespace allow you to query the type’s fields, methods, properties, and events by parsing the corresponding metadata tables. If you want to write an assembly that you can make use of, then dump an assembly and study its information. An invaluable tool used to do exactly that is called the .NET Reflector.

References

  • Professional .NET Framework 2.0, written by Joe Duffy

History

  • 27th August, 2010: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here