Document Sample
indexer Powered By Docstoc
					Indexer Overview
Defining an indexer allows you to create classes that act like "virtual arrays." Instances of that class can be accessed
using the [] array access operator. Defining an indexer in C# is similar to defining operator [] in C++, but is
considerably more flexible. For classes that encapsulate array- or collection-like functionality, using an indexer allows
the users of that class to use the array syntax to access the class.

Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties except that
their accessors take parameters.

         Indexers enable objects to be indexed in a similar manner to arrays.
         A get accessor returns a value. A set accessor assigns a value.
         The this keyword is used to define the indexers.
         The value keyword is used to define the value being assigned by the set indexer.
         Indexers do not have to be indexed by an integer value; it is up to you how to define the specific look-up
         Indexers can be overloaded.
         Indexers can have more than one formal parameter, for example, when accessing a two-dimensional array.

Something about indexer

         Indexer Concept is object act as an array.
         Indexer an object to be indexed in the same way as an array.
         Indexer modifier can be private, public, protected or internal.
         The return type can be any valid C# types.
         Indexers in C# must have at least one parameter. Else the compiler will generate a compilation error.

Example :

class SampleCollection<T>
   // Declare an array to store the data elements.
   private T[] arr = new T[100];

    // Define the indexer, which will allow client code
    // to use [] notation on the class instance itself.
    // (See line 2 of code in Main below.)
    public T this[int i]
         // This indexer is very simple, and just returns or sets
         // the corresponding element from the internal array.
         return arr[i];
         arr[i] = value;

// This class shows how client code uses the indexer.
class Program
   static void Main(string[] args)
        // Declare an instance of the SampleCollection type.
        SampleCollection<string> stringCollection = new SampleCollection<string>();

        // Use [] notation on the type.
        stringCollection[0] = "Hello, World";

Reflection Overview
Reflection is the ability of a managed code to read its own metadata for the purpose of finding assemblies, modules
and type information at runtime. In other words, reflection provides objects that encapsulate assemblies, modules
and types. A program reflects on itself by extracting metadata from its assembly and using that metadata either to
inform the user or to modify its own behavior. Reflection is similar to C++ RTTI (Runtime Type Information), but
much broader in scope and capability. By using Reflection in C#, one is able to find out details of an object, method,
and create objects and invoke methods at runtime. The System.Reflection namespace contains classes and
interfaces that provide a managed view of loaded types, methods, and fields, with the ability to dynamically create
and invoke types. When writing a C# code that uses reflection, the coder can use the typeof operator to get the
object's type or use the GetType() method to get the type of the current instance. Here are sample codes that
demonstrate the use of reflection:

Reflection allows the inspection of metadata in a PE file and late binding (run time) to types and their members. The
System.Reflection namespace defines the following types to analyze the module's metadata of an assembly:
Assembly, Module, Enum, ParameterInfo, MemberInfo, Type, MethodInfo, ConstructorInfo, FieldInfo, EventInfo, and

The System.Type class is the main class for reflection. The System.Type class is an abstract class and that represents a
type in the Common Type System (CLR). By using this class, we can find the type name, the types used in a module
(an assembly may contain one or more modules) and namespace, and to see whether a given type is a value or a
reference type, and so on. It also allows us to query the type's fields, methods, properties, and events by parsing the
corresponding metadata tables. FCL's Serialization mechanism uses reflection to determine what fields a type
defines. The serialization formatter then can obtain the values of these fields and write them into the byte stream.

Late bindings can be achieved by using reflection. For example, in some applications, we don't know which assembly
to load during compile time, so we ask the user to enter the assembly name and type during run time and the
application can load assembly. For this purpose, the System.Reflection.Assembly type offers three static methods
that allow you to explicitly load an assembly: Load, LoadFrom, and LoadWithPartialName. These methods are
something similar to the LoadLibrary Win32 API. As our System.Reflection namespace is going to work with assembly
and metadata, let's see something about assembly and metadata.

           When you need to access attributes in your program's metadata. See the topic Accessing Attributes With
           For examining and instantiating types in an assembly.
           For building new types at runtime. Use classes in System.Reflection.Emit.
           For performing late binding, accessing methods on types created at run time. See the topic Dynamically
            Loading and Using Types.
Assembly and Metadata

An assembly is a logical DLL or EXE, and a manifest is a detailed description (metadata) of an assembly. The .NET
compiler produces a portable executable PE file for CLR with the extensions of .exe or .dll. This PE file is mainly
comprised of metadata and IL (Intermediate Language). Metadata contains a number of different tables; for
example, a type definition table, a filed definition table, a method definition table, and so forth. By parsing these
tables, we can get an assembly's types and attributes. The FCL's System.Reflection namespace supports several types
to reflect over or parse these metadata tables.

PE (Portable Executable) = Metadata (bunch definition tables) + IL (Microsoft Intermediate Language) + Some other
data which are not relevant to this article.

Create instance from dynamically loaded assembly

All the following examples try to access to sample class Calculator from Test.dll assembly. The calculator class can be
defined like this.


namespace Test
  public class Calculator
    public Calculator() { ... }
    private double _number;
    public double Number { get { ... } set { ... } }
    public void Clear() { ... }
    private void DoClear() { ... }
    public double Add(double number) { ... }
    public static double Pi { ... }
    public static double GetPi() { ... }

Examples of using reflection to load the Test.dll assembly, to create instance of the Calculator class and to access
its members (public/private, instance/static).


// dynamically load assembly from file Test.dll
Assembly testAssembly = Assembly.LoadFile(@"c:\Test.dll");


// get type of class Calculator from just loaded assembly
Type calcType = testAssembly.GetType("Test.Calculator");


// create instance of class Calculator
object calcInstance = Activator.CreateInstance(calcType);


// get info about property: public double Number
PropertyInfo numberPropertyInfo = calcType.GetProperty("Number");


// get value of property: public double Number
double value = (double)numberPropertyInfo.GetValue(calcInstance, null);


// set value of property: public double Number
numberPropertyInfo.SetValue(calcInstance, 10.0, null);


// get info about static property: public static double Pi
PropertyInfo piPropertyInfo = calcType.GetProperty("Pi");


// get value of static property: public static double Pi
double piValue = (double)piPropertyInfo.GetValue(null, null);


// invoke public instance method: public void Clear()
  BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
  null, calcInstance, null);


// invoke private instance method: private void DoClear()
  BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
  null, calcInstance, null);


// invoke public instance method: public double Add(double number)
double value = (double)calcType.InvokeMember("Add",
  BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
  null, calcInstance, new object[] { 20.0 });


// invoke public static method: public static double GetPi()
double piValue = (double)calcType.InvokeMember("GetPi",
  BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public,
  null, null, null);


// get value of private field: private double _number
double value = (double)calcType.InvokeMember("_number",
  BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic,
  null, calcInstance, null);

Shared By: