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() {
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly a in assemblies) {
WriteLine(0, "Assembly: {0}", a);
foreach (Type t in a.GetExportedTypes()) {
WriteLine(1, "Type: {0}", t);
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";
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