- •Contents
- •What Is C#?
- •C# Versus Other Programming Languages
- •Preparing to Program
- •The Program Development Cycle
- •Your First C# Program
- •Types of C# Programs
- •Summary
- •Workshop
- •C# Applications
- •Basic Parts of a C# Application
- •Structure of a C# Application
- •Analysis of Listing 2.1
- •Object-Oriented Programming (OOP)
- •Displaying Basic Information
- •Summary
- •Workshop
- •Variables
- •Using Variables
- •Understanding Your Computer’s Memory
- •C# Data Types
- •Numeric Variable Types
- •Literals Versus Variables
- •Constants
- •Reference Types
- •Summary
- •Workshop
- •Types of Operators
- •Punctuators
- •The Basic Assignment Operator
- •Mathematical/Arithmetic Operators
- •Relational Operators
- •Logical Bitwise Operators
- •Type Operators
- •The sizeof Operator
- •The Conditional Operator
- •Understanding Operator Precedence
- •Converting Data Types
- •Understanding Operator Promotion
- •For Those Brave Enough
- •Summary
- •Workshop
- •Controlling Program Flow
- •Using Selection Statements
- •Using Iteration Statements
- •Using goto
- •Nesting Flow
- •Summary
- •Workshop
- •Introduction
- •Abstraction and Encapsulation
- •An Interactive Hello World! Program
- •Basic Elements of Hello.cs
- •A Few Fundamental Observations
- •Summary
- •Review Questions
- •Programming Exercises
- •Introduction
- •Essential Elements of SimpleCalculator.cs
- •A Closer Look at SimpleCalculator.cs
- •Simplifying Your Code with Methods
- •Summary
- •Review Questions
- •Programming Exercises
- •Introduction
- •Lexical Structure
- •Some Thoughts on Elevator Simulations
- •Concepts, Goals and Solutions in an Elevator Simulation Program: Collecting Valuable Statistics for Evaluating an Elevator System
- •A Deeper Analysis of SimpleElevatorSimulation.cs
- •Class Relationships and UML
- •Summary
- •Review Questions
- •Programming Exercises
- •The Hello Windows Forms Application
- •Creating and Using an Event Handler
- •Defining the Border Style of the Form
- •Adding a Menu
- •Adding a Menu Shortcut
- •Handling Events from Menus
- •Dialogs
- •Creating Dialogs
- •Using Controls
- •Data Binding Strategies
- •Data Binding Sources
- •Simple Binding
- •Simple Binding to a DataSet
- •Complex Binding of Controls to Data
- •Binding Controls to Databases Using ADO.NET
- •Creating a Database Viewer with Visual Studio and ADO.NET
- •Resources in .NET
- •Localization Nuts and Bolts
- •.NET Resource Management Classes
- •Creating Text Resources
- •Using Visual Studio.NET for Internationalization
- •Image Resources
- •Using Image Lists
- •Programmatic Access to Resources
- •Reading and Writing RESX XML Files
- •The Basic Principles of GDI+
- •The Graphics Object
- •Graphics Coordinates
- •Drawing Lines and Simple Shapes
- •Using Gradient Pens and Brushes
- •Textured Pens and Brushes
- •Tidying up Your Lines with Endcaps
- •Curves and Paths
- •The GraphicsPath Object
- •Clipping with Paths and Regions
- •Transformations
- •Alpha Blending
- •Alpha Blending of Images
- •Other Color Space Manipulations
- •Using the Properties and Property Attributes
- •Demonstration Application: FormPaint.exe
- •Why Use Web Services?
- •Implementing Your First Web Service
- •Testing the Web Service
- •Implementing the Web Service Client
- •Understanding How Web Services Work
- •Summary
- •Workshop
- •How Do Web References Work?
- •What Is UDDI?
- •Summary
- •Workshop
- •Passing Parameters and Web Services
- •Accessing Data with Web Services
- •Summary
- •Workshop
- •Managing State in Web Services
- •Dealing with Slow Services
- •Workshop
- •Creating New Threads
- •Synchronization
- •Summary
- •The String Class
- •The StringBuilder Class
- •String Formatting
- •Regular Expressions
- •Summary
- •Discovering Program Information
- •Dynamically Activating Code
- •Reflection.Emit
- •Summary
- •Simple Debugging
- •Conditional Debugging
- •Runtime Tracing
- •Making Assertions
- •Summary
582
Extreme C#
PART IV
Reflection is the capability to inspect the metadata of a program and gather information about its types. Using reflection, it’s possible to learn about program assemblies, modules, and all types of internal program elements.
This is particularly useful for design tools, supporting the automated building of code based on user selections derived from the metadata of the underlying types being used. Reflection also provides excellent support for late-bound frameworks where runtime determination is required for selecting required libraries or other functionality on-the-fly.
Discovering Program Information
The reflection API is based on a hierarchical model where higher-level items are composed of one or more lower-level items. Figure 28.1 shows this hierarchy. Assemblies, the basic unit of program distribution in C#, are at the top. Assemblies may be composed of one or more modules. Modules may have one or more types. Types are program elements such as classes, structs, delegates, and enums. Types may contain one or more fields, properties, methods, or events, depending on the type. It may be handy to think about this model as you progress through the sections of this chapter.
FIGURE 28.1 |
Assembly |
Reflection API hierarchy.
1..*
Module
|
1..* |
|
May be class, |
Type |
|
delegate, |
||
|
||
enum, or struct |
|
1..* |
1..* |
1..* |
|
1..* |
Event |
Field |
|
Property |
Method |
Reflection
CHAPTER 28
583
The primary purpose of reflection is to discover program information. The C# reflection API makes it possible to find out all information available about a program. The program elements to be searched include assemblies, modules, types, and type members. Listing 28.1 creates a class that will be reflected upon, and Listing 28.2 demonstrates how to obtain the various reflection objects and inspect their available information.
LISTING 28.1 Class to Reflect Upon: Reflected.cs
using System;
using System.Collections;
///<summary>
///Reflected Class
///</summary>
public class Reflected
{
public |
int |
MyField; |
protected |
ArrayList myArray; |
public Reflected()
{
myArray = new ArrayList(); myArray.Add(“Some ArrayList Entry”);
}
public float MyProperty
{
get
{
return MyEvent();
}
}
public object this[int index]
{
get
{
if (index <= index)
{
return myArray[index];
}
else
{
return null;
}
}
set
{
28
EFLECTIONR
584
Extreme C#
PART IV
LISTING 28.1 continued
myArray.Add(value);
}
}
public float MyInstanceMethod()
{
Console.WriteLine(“Invoking Instance MyMethod.”);
return 0.02f;
}
public static float MyStaticMethod()
{
Console.WriteLine(“Invoking Static MyMethod.”);
return 0.02f;
}
public delegate float MyDelegate();
public event MyDelegate MyEvent
= new MyDelegate(MyStaticMethod);
public enum MyEnum { valOne, valTwo, valThree };
}
LISTING 28.2 Performing Reflection: Reflecting.cs
using System;
using System.Reflection;
///<summary>
///Performing Reflection.
///</summary>
class Reflecting
{
static void Main(string[] args)
{
Reflecting reflect = new Reflecting();
Assembly myAssembly
= Assembly.LoadFrom(“Reflecting.exe”);
reflect.GetReflectionInfo(myAssembly);
}
void GetReflectionInfo(Assembly myAssembly)
{
Type[] typeArr = myAssembly.GetTypes();
LISTING 28.2 continued
foreach (Type type in typeArr)
{
Console.WriteLine(“\nType: {0}\n”, type.FullName);
ConstructorInfo[] MyConstructors = type.GetConstructors();
foreach (ConstructorInfo constructor in MyConstructors)
{
Console.WriteLine(“\tConstructor: {0}”, constructor.ToString());
}
Console.WriteLine();
FieldInfo[] MyFields = type.GetFields(); foreach (FieldInfo field in MyFields)
{
Console.WriteLine(“\tField: {0}”, field.ToString());
}
Console.WriteLine();
MethodInfo[] MyMethods = type.GetMethods(); foreach (MethodInfo method in MyMethods)
{
Console.WriteLine(“\tMethod: {0}”, method.ToString());
}
Console.WriteLine();
PropertyInfo[] MyProperties
= type.GetProperties();
foreach (PropertyInfo property in MyProperties)
{
Console.WriteLine(“\tProperty: {0}”, property.ToString());
}
Console.WriteLine();
EventInfo[] MyEvents = type.GetEvents(); foreach (EventInfo anEvent in MyEvents)
{
Console.WriteLine(“\tEvent: {0}”, anEvent.ToString());
}
Console.WriteLine();
}
}
}
Reflection
CHAPTER 28
585
28
EFLECTIONR
586
Extreme C#
PART IV
And the output is:
Type: Reflecting
Constructor: Void .ctor()
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: System.Type GetType()
Type: Reflected
Constructor: Void .ctor()
Field: Int32 MyField
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: Single get_MyProperty()
Method: System.Object get_Item(Int32)
Method: Void set_Item(Int32, System.Object)
Method: Single MyInstanceMethod()
Method: Single MyStaticMethod()
Method: Void add_MyEvent(MyDelegate)
Method: Void remove_MyEvent(MyDelegate)
Method: System.Type GetType()
Property: Single MyProperty
Property: System.Object Item [Int32]
Event: MyDelegate MyEvent
Type: Reflected+MyDelegate
Constructor: Void .ctor(System.Object, UIntPtr)
Method: Single EndInvoke(System.IAsyncResult)
Method: System.IAsyncResult BeginInvoke(
System.AsyncCallback,
System.Object)
Method: Single Invoke()
Method: Void GetObjectData(
Reflection
CHAPTER 28
System.Runtime.Serialization.SerializationInfo,
System.Runtime.Serialization.StreamingContext)
Method: System.Object Clone()
Method: System.Delegate[] GetInvocationList()
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: System.Object DynamicInvoke(System.Object[])
Method: System.Reflection.MethodInfo get_Method()
Method: System.Object get_Target()
Method: System.Type GetType()
Property: System.Reflection.MethodInfo Method
Property: System.Object Target
Type: Reflected+MyEnum
Field: Int32 value__
Field: MyEnum valOne
Field: MyEnum valTwo
Field: MyEnum valThree
Method: System.String ToString(System.IFormatProvider)
Method: System.TypeCode GetTypeCode()
Method: System.String ToString(System.String,
System.IFormatProvider)
Method: Int32 CompareTo(System.Object)
Method: Int32 GetHashCode()
Method: Boolean Equals(System.Object)
Method: System.String ToString()
Method: System.String ToString(System.String)
Method: System.Type GetType()
The primary purpose of Listing 28.1 is to have a class available with all types of class members to reflect upon. It does nothing more than serve that purpose, and all of its program elements should be familiar by now.
Listing 28.2 is where the interesting bits are. The Main() method obtains an assembly object by calling the static LoadFrom() method of the Assembly class. The LoadFrom() method has a string parameter, specifying the name of the executable file, or assembly, to load.
Within the GetReflectionInfo() method, the Assembly object, myAssembly, invokes its GetTypes() method to obtain an array of all types available in the assembly.
587
28
EFLECTIONR