Category Archives: Reflection

Reflection (part 6, professional), Emit

Reflection can discover information about objects at runtime and execute against those objects. The namespace System.Reflection.Emit also allows you to build assemblies and create types at runtime. Only a few programmers will come across Emit. You have to be a kind of Rambo sewing yourself while fighting … and definitely not Alice in Wonderland.

Emit generates IL code in memory. The source code for such is quite complex and difficult. We are nearly back to Assembler style. And if you remember well, crashes and difficult debugging were the order of the day. There are tools like the EmitHelper class out there to make Emit easier. I am going to show the fundamentals today, this does not cover tools.

Today’s word list:

Domain
Application domains aid security, separating applications from each other and each other’s data. A single process can run several application domains, with the same level of isolation that would exist in separate processes. Running multiple applications within a single process increases server scalability.
Faults in one application domain cannot affect other code running in another application domain.

Module
A module is a portable executable file, such as type.dll or application.exe, consisting of one or more classes and interfaces. There may be multiple namespaces contained in a single module, and a namespace may span multiple modules.
One or more modules deployed as a unit compose an assembly.

The hierarchy is: domain => assemblies => modules => classes => functions


Ildasm.exe

A disassembler for MSIL code.

The first step is to create an executable file from:

using System;
using System.Reflection;

namespace HelloWorld {
    public class Program {
        static void Main(string[] args) {
        } //
        

        public string Test() {
            return string.Format("DateTime is {0:dd MMM yyyy  HH:mm:ss}", DateTime.Now);
        } //

        public string Test2() {
            return DateTime.UtcNow.ToString();
        } //
        
        public string Test3() {
            return Assembly.GetExecutingAssembly().ToString();
        } //

        public void Test4() {
            Console.WriteLine("hello world !");
        } //

    } // class
} // namespace

On the windows taskbar, click Start, click All Programs, click Visual Studio, click Visual Studio Tools, and then click Visual Studio Command Prompt.
-or-
If you have the Windows SDK installed on your computer: On the taskbar, click Start, click All Programs, click the folder for the Windows SDK, and then click Command Prompt (or CMD Shell).

Change to the right folder and enter “ildasm HelloWorld.exe /output:HelloWorld.il”.

ILDASM

In your folder you should see something like this:

SnapShot

Open the HelloWorld.il file in a text editor and delve into the following sections:

method Test()

  .method public hidebysig instance string 
          Test() cil managed
  {
    // Code size       21 (0x15)
    .maxstack  8
    IL_0000:  ldstr      "DateTime is {0:dd MMM yyyy  HH:mm:ss}"
    IL_0005:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
    IL_000a:  box        [mscorlib]System.DateTime
    IL_000f:  call       string [mscorlib]System.String::Format(string,
                                                                object)
    IL_0014:  ret
  } // end of method Program::Test

method Test3()

  .method public hidebysig instance string 
          Test2() cil managed
  {
    // Code size       20 (0x14)
    .maxstack  1
    .locals init ([0] valuetype [mscorlib]System.DateTime CS$0$0000)
    IL_0000:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_UtcNow()
    IL_0005:  stloc.0
    IL_0006:  ldloca.s   CS$0$0000
    IL_0008:  constrained. [mscorlib]System.DateTime
    IL_000e:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_0013:  ret
  } // end of method Program::Test2

method Test3()

  .method public hidebysig instance string 
          Test3() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  call       class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly()
    IL_0005:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_000a:  ret
  } // end of method Program::Test3

method Test4()

  .method public hidebysig instance void 
          Test4() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  ldstr      "hello world !"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method Program::Test4

These code sections give you a rough idea of what we are going to code in runtime.
Start a new console project. You have to edit the file “AssemblyInfo.cs”. Add the assembly attribute AllowPartiallyTrustedCallersAttribute. The program won’t run otherwise. We are on a low coding level and Microsoft obviously tries to protect code especially on that level.

AssemblyInfo.cs

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("oink")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("blablabla")]
[assembly: AssemblyCopyright("Copyright ©  2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AllowPartiallyTrustedCallersAttribute]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0bf893aa-f3da-49ef-a2dc-a63d8ffc9ead")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

The Print() method is not big, nevertheless you find something unusual here. The keyword __arglist is not official. It has been implemented by Microsoft, but is not documented at all. It is also not well supported in C#. For instance you cannot use a foreach loop. __arglist takes any number of optional arguments like object[]. In our example it does make a big difference to use __arglist. We do not have to create an array and fill it in. This would be much more code in Emit. On the contrary the __arglist algorithm is quite short and comfortable. Follow the link for more __arglist documentation.

public static void Print(string xHeader, __arglist) {
    ArgIterator lIterator = new ArgIterator(__arglist);

    Console.WriteLine(xHeader);
    while (lIterator.GetRemainingCount() > 0) {
        TypedReference r = lIterator.GetNextArg();
        object o = TypedReference.ToObject(r);
        Console.Write(o);
    }
    Console.WriteLine();
    Console.WriteLine();
} //

EmitCode() is the actual code generation part. Let’s call the remaining source code “administration” to simplify the situation.
There are two ways to get the MethodInfo for a property. One is used for DateTime.Now, the other one is used for DateTime.UtcNow .
They can be used equally. I used both ways for demonstration purposes only.
I tried to keep the example simple. You don’t have to study the MSIL to understand the code. Some information about MSIL OpCodes can be found here.

static void EmitCode(ILGenerator xILGenerator) {
    MethodInfo lMethodInfo_Print = typeof(EmitDemo).GetMethod("Print");
    MethodInfo lDateTime_Now = typeof(DateTime).GetProperty("Now").GetGetMethod();
    MethodInfo lFormat = typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) });

    xILGenerator.Emit(OpCodes.Ldstr, "DateTime is {0:dd MMM yyyy  HH:mm:ss}");
    xILGenerator.Emit(OpCodes.Call, lDateTime_Now);
    xILGenerator.Emit(OpCodes.Box, typeof(DateTime));
    xILGenerator.Emit(OpCodes.Call, lFormat);
    xILGenerator.EmitCall(OpCodes.Call, lMethodInfo_Print, new Type[] { });

    xILGenerator.Emit(OpCodes.Ldstr, "This equals UTC: ");
    xILGenerator.Emit(OpCodes.Call, typeof(DateTime).GetMethod("get_UtcNow"));  // compare this with lDateTime_Now (== same, just another demo approach)
    xILGenerator.EmitCall(OpCodes.Call, lMethodInfo_Print, new Type[] { typeof(DateTime) });

    xILGenerator.Emit(OpCodes.Ldstr, "The assembly is: ");
    xILGenerator.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetExecutingAssembly"));
    xILGenerator.EmitCall(OpCodes.Call, lMethodInfo_Print, new Type[] { typeof(Assembly) });

    xILGenerator.Emit(OpCodes.Ldstr, "Console.WriteLine() is old school.");
    xILGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }));

    xILGenerator.EmitWriteLine("EmitWriteLine() is for lazy programmers.");

    xILGenerator.Emit(OpCodes.Ret);
} //

Test1_ViaFullAssembly() shows you how to properly initialize and use an assembly. Remember the hierarchy from above: domain => assemblies => modules => classes => functions
The method is build like a chain. Each statement uses the result of the previous one.

public static void Test1_ViaFullAssembly() {
    AssemblyName lAssemblyName = new AssemblyName("MyAssembly");
    AssemblyBuilder lAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(lAssemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder lModuleBuilder = lAssemblyBuilder.DefineDynamicModule("MyModule");
    TypeBuilder lTypeBuilder = lModuleBuilder.DefineType("MyType");
    MethodBuilder lMethodBuilder = lTypeBuilder.DefineMethod("DoSomething", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(void), Type.EmptyTypes);
    EmitCode(lMethodBuilder.GetILGenerator());

    Type lType = lTypeBuilder.CreateType();
    lType.GetMethod("DoSomething").Invoke(null, null);

    Console.ReadLine();
} //

example output:
DateTime is 15 Jan 2014 23:17:30

This equals UTC:
15/01/2014 23:17:30

The assembly is:
MyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Console.WriteLine() is old school.
EmitWriteLine() is for lazy programmers.

You can avoid building a full assembly. DynamicMethod simplifies the dynamic creation of methods. Of course you won’t have any class structure. The method is super-public, it reminds me of VBA modules.

public static void ViaDynamicMethod() {
    DynamicMethod lDynamicMethod = new DynamicMethod("DoSomething", typeof(void), Type.EmptyTypes, typeof(object));
    EmitCode(lDynamicMethod.GetILGenerator());
    lDynamicMethod.Invoke(null, null);
    Console.ReadLine();
} //

example output:
DateTime is 15 Jan 2014 23:17:58

This equals UTC:
15/01/2014 23:17:58

The assembly is:
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Console.WriteLine() is old school.
EmitWriteLine() is for lazy programmers.

Advertisements

Reflection (part 5, professional), CodeDOM (& lambda expression tree)

Today’s post is about code generation at runtime using CodeDOM, which is the logical step before runtime code generation using Emit. The .Net framework has been built in an amazing way. We can easily neglect some flaws. Compared to Java there are no flaws at all. Jealousy needs to be deserved, sympathy is for free. Somehow Java is for free, and this is what you get.

Make sure, you are aware of the following differences. There are Expression and Statement. Please follow the links if you feel uncertain about the definitions.

Expression
An expression is a sequence of one or more operands and zero or more operators that can be evaluated to a single value, object, method, or namespace.

Statement
The actions that a program takes are expressed in statements. Common actions include declaring variables, assigning values, calling methods, looping through collections, and branching to one or another block of code, depending on a given condition. The order in which statements are executed in a program is called the flow of control or flow of execution.
A statement can consist of a single line of code that ends in a semicolon, or a series of single-line statements in a block. A statement block is enclosed in {} brackets and can contain nested blocks.

Succinct:
An Expression is a kind of mathematical or logical expression.
A Statement is a single code instruction or block of code to execute.

The first example code generates source code for C# and VB and saves the generated files on your desktop. Of course it has to be the classical “hello world” program.
CodeDOM stands for Code Document Object Model. It is located in the System.CodeDom namespace and provides methods to create code at runtime.

// what you need for the code example:
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

First of all you have to create a compile unit object CodeCompileUnit. It is the top container for namespaces, classes and members. Then add the components as follows:

public static void Test() {
    CodeCompileUnit lUnit = new CodeCompileUnit();

    CodeNamespace lNamespace = new CodeNamespace("MyNamespace");
    lNamespace.Imports.Add(new CodeNamespaceImport("System"));
    lNamespace.Imports.Add(new CodeNamespaceImport("System.IO"));     // not used, just for demo
    lUnit.Namespaces.Add(lNamespace);

    CodeTypeDeclaration lClass = new CodeTypeDeclaration("MyClass");
    CodeMethodInvokeExpression lExpression = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("Console"), "WriteLine", new CodePrimitiveExpression("hello world !"));
    lNamespace.Types.Add(lClass);

    // write Main entry point method
    CodeEntryPointMethod lMain = new CodeEntryPointMethod();
    lMain.Statements.Add(lExpression);
    lClass.Members.Add(lMain);

    // write another method
    CodeMemberMethod lMethod = new CodeMemberMethod();
    lMethod.Name = "DoSomething";
    lClass.Members.Add(lMethod);

    string lDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\";
    CodeGeneratorOptions lOptions = new CodeGeneratorOptions();
    lOptions.IndentString = "  "; // or "\t";
    lOptions.BlankLinesBetweenMembers = true;

    // generate a C# source code file
    CSharpCodeProvider lCSharpCodeProvider = new CSharpCodeProvider();
    using (StreamWriter lStreamWriter = new StreamWriter(lDesktopPath + "HelloWorld.cs", false)) {
        lCSharpCodeProvider.GenerateCodeFromCompileUnit(lUnit, lStreamWriter, lOptions);
    }

    // generate a VB source code file
    VBCodeProvider lVBCodeProvider = new VBCodeProvider();
    using (StreamWriter lStreamWriter = new StreamWriter(lDesktopPath + "HelloWorld.vb", false)) {
        lVBCodeProvider.GenerateCodeFromCompileUnit(lUnit, lStreamWriter, lOptions);
    }
            
} //

example output file HelloWorld.cs:

//------------------------------------------------------------------------------
// 
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.18408
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// 
//------------------------------------------------------------------------------

namespace MyNamespace {
  using System;
  using System.IO;
  
  
  public class MyClass {
    
    public static void Main() {
      Console.WriteLine("hello world !");
    }
    
    private void DoSomething() {
    }
  }
}

example output file HelloWorld.vb:

'------------------------------------------------------------------------------
' 
'     This code was generated by a tool.
'     Runtime Version:4.0.30319.18408
'
'     Changes to this file may cause incorrect behavior and will be lost if
'     the code is regenerated.
' 
'------------------------------------------------------------------------------

Option Strict Off
Option Explicit On

Imports System
Imports System.IO

Namespace MyNamespace
  
  Public Class [MyClass]
    
    Public Shared Sub Main()
      Console.WriteLine("hello world !")
    End Sub
    
    Private Sub DoSomething()
    End Sub
  End Class
End Namespace

In the above example I have added an empty method. We will make it more complex now. The method will be called with parameters from Main() and return a value to a local variable. The local variable will be stored in a field via a property.

public static void Test2() {
    CodeCompileUnit lUnit = new CodeCompileUnit();

    CodeNamespace lNamespace = new CodeNamespace("MyNamespace");
    lNamespace.Imports.Add(new CodeNamespaceImport("System"));
    lUnit.Namespaces.Add(lNamespace);

    CodeTypeDeclaration lClass = new CodeTypeDeclaration("MyClass");
    lClass.IsClass = true;
    lClass.Attributes = MemberAttributes.Public;
    lNamespace.Types.Add(lClass);


    // -----------------------------------------------
    // method DoSomething()
    // -----------------------------------------------

    CodeTypeParameter lClassAsParameter = new CodeTypeParameter(lClass.Name);
    CodeTypeReference lClassReference = new CodeTypeReference(lClassAsParameter);
    CodeParameterDeclarationExpression lClassExpression = new CodeParameterDeclarationExpression(lClassReference, "xClass");
    CodeMemberMethod lDoSomething = new CodeMemberMethod();
    lDoSomething.Attributes = MemberAttributes.Public;
    lDoSomething.Comments.Add(new CodeCommentStatement("This is an example comment for our method DoSomething()."));
    lDoSomething.Name = "DoSomething";
    lDoSomething.ReturnType = new CodeTypeReference(typeof(double));
    lDoSomething.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "xInteger"));
    lDoSomething.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "xString"));
    lDoSomething.Parameters.Add(lClassExpression);
    lDoSomething.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(1.0)));
    lClass.Members.Add(lDoSomething);


    // -----------------------------------------------
    // private field _MyField
    // -----------------------------------------------

    CodeMemberField lField = new CodeMemberField(typeof(long), "_MyField");
    lField.Attributes = MemberAttributes.Private;
    lField.InitExpression = new CodePrimitiveExpression(10);
    lClass.Members.Add(lField);


    // -----------------------------------------------
    // property MyProperty
    // -----------------------------------------------

    CodeMemberProperty lProperty = new CodeMemberProperty();
    lProperty.Name = "MyProperty";
    lProperty.Attributes = MemberAttributes.Public;
    lProperty.Type = new CodeTypeReference(typeof(long));
    lProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(359)));
    lProperty.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), lField.Name), new CodePropertySetValueReferenceExpression()));
    lClass.Members.Add(lProperty);


    // -----------------------------------------------
    // Main()
    // -----------------------------------------------

    CodeEntryPointMethod lMain = new CodeEntryPointMethod();
    lClass.Members.Add(lMain);

    // local double variable d
    CodeVariableReferenceExpression lLocalVariable_d = new CodeVariableReferenceExpression("d");
    CodeVariableDeclarationStatement lLocalVariableStatement_d = new CodeVariableDeclarationStatement(typeof(double), lLocalVariable_d.VariableName);
    lMain.Statements.Add(lLocalVariableStatement_d);

    // local integer variable i
    CodeVariableReferenceExpression lLocalVariable_i = new CodeVariableReferenceExpression("i");
    CodeVariableDeclarationStatement lLocalVariableStatement_i = new CodeVariableDeclarationStatement(typeof(int), lLocalVariable_i.VariableName);
    lLocalVariableStatement_i.InitExpression = new CodePrimitiveExpression(0);
    lMain.Statements.Add(lLocalVariableStatement_i);

    // local class variable MyClass
    CodeVariableReferenceExpression lLocalVariable_Class = new CodeVariableReferenceExpression("lClass");
    CodeVariableDeclarationStatement lLocalVariableStatement_Class = new CodeVariableDeclarationStatement(lClassReference, lLocalVariable_Class.VariableName);
    lLocalVariableStatement_Class.InitExpression = new CodeObjectCreateExpression(lClass.Name, new CodeExpression[] { });
    lMain.Statements.Add(lLocalVariableStatement_Class);

    // DoSomething() method call
    CodeMethodInvokeExpression lDoSomethingExpression = new CodeMethodInvokeExpression(lLocalVariable_Class, lDoSomething.Name, new CodeExpression[] { lLocalVariable_i, new CodePrimitiveExpression("hello"), lLocalVariable_Class});
    CodeAssignStatement lAssignment = new CodeAssignStatement(lLocalVariable_d, lDoSomethingExpression);
    lMain.Statements.Add(lAssignment);
    //lMain.Statements.Add(lDoSomethingExpression); // without assignment

    // cast the "double" result to type "long" and write it to field _MyField via property MyProperty
    CodePropertyReferenceExpression lPropertyExpression = new CodePropertyReferenceExpression(lLocalVariable_Class, lProperty.Name);
    CodeCastExpression lCastExpression = new CodeCastExpression(typeof(long), lLocalVariable_d);
    lAssignment = new CodeAssignStatement(lPropertyExpression, lCastExpression);
    lMain.Statements.Add(lAssignment);

    // -----------------------------------------------
    // create source code
    // -----------------------------------------------

    string lDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\";
    CodeGeneratorOptions lOptions = new CodeGeneratorOptions();
    lOptions.IndentString = "  "; // or "\t";
    lOptions.BlankLinesBetweenMembers = true;

    // generate a C# source code file
    CSharpCodeProvider lCSharpCodeProvider = new CSharpCodeProvider();
    using (StreamWriter lStreamWriter = new StreamWriter(lDesktopPath + "MoreComplex.cs", false)) {
        lCSharpCodeProvider.GenerateCodeFromCompileUnit(lUnit, lStreamWriter, lOptions);
    }
} //

example output:

//------------------------------------------------------------------------------
// 
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.18408
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// 
//------------------------------------------------------------------------------

namespace MyNamespace {
  using System;
  
  
  public class MyClass {
    
    private long _MyField = 10;
    
    public virtual long MyProperty {
      get {
        return 359;
      }
      set {
        this._MyField = value;
      }
    }
    
    // This is an example comment for our method DoSomething().
    public virtual double DoSomething(int xInteger, string xString, MyClass xClass) {
      return 1D;
    }
    
    public static void Main() {
      double d;
      int i = 0;
      MyClass lClass = new MyClass();
      d = lClass.DoSomething(i, "hello", lClass);
      lClass.MyProperty = ((long)(d));
    }
  }
}

Is your head burning already? This was quite complex. As usual there are easier ways for lazy people. I do not recommend any shortcuts. It undermines the idea of flexibility.

public static void Test3() {
    CodeCompileUnit lUnit = new CodeCompileUnit();

    CodeNamespace lNamespace = new CodeNamespace("MyNamespace");
    lNamespace.Imports.Add(new CodeNamespaceImport("System"));
    lUnit.Namespaces.Add(lNamespace);

    CodeTypeDeclaration lClass = new CodeTypeDeclaration("MyClass");
    lNamespace.Types.Add(lClass);

    // write Main entry point method
    CodeEntryPointMethod lMain = new CodeEntryPointMethod();
    lMain.Statements.Add(new CodeSnippetExpression("Console.WriteLine(\"hello world !\")"));
    lClass.Members.Add(lMain);

    string lDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\";
    CodeGeneratorOptions lOptions = new CodeGeneratorOptions();
    lOptions.IndentString = "  "; // or "\t";
    lOptions.BlankLinesBetweenMembers = true;

    // generate a C# source code file
    CSharpCodeProvider lCSharpCodeProvider = new CSharpCodeProvider();
    using (StreamWriter lStreamWriter = new StreamWriter(lDesktopPath + "HelloWorldForLazyPeople.cs", false)) {
        lCSharpCodeProvider.GenerateCodeFromCompileUnit(lUnit, lStreamWriter, lOptions);
    }
} //

We created source code in the runtime environment. How can we execute it?
The next example compiles a class into an assembly and then executes the Main() method, which is automatically defined as the entry point. This happens in memory. If you want to write the executable code to a disk, then set GenerateInMemory to false and define a proper OutputAssembly path in the compiler parameters (variable lParameters). Use CompileAssemblyFromFile() instead of CompileAssemblyFromSource(). Btw. CompileAssemblyFromDom() would accept CodeCompileUnits (eg. used in Test2) as input data. Therefore you don’t have to generate a source code file to compile your code structure.

private static string[] _MyCode = new string[] { 
    "using System;" +
    "public class MyClass {"  +
    "public static void Main() { Console.WriteLine(\"hello world !\"); }" +
    "}" };


public static void Test4() {
    CSharpCodeProvider lCodeProvider= new CSharpCodeProvider();
    CompilerParameters lParameters = new CompilerParameters();
    //lParameters.ReferencedAssemblies.Add("System.dll");
    lParameters.GenerateInMemory = true;
    lParameters.GenerateExecutable = true;
    lParameters.OutputAssembly = "HelloWorld";

    CompilerResults lCompilerResults = lCodeProvider.CompileAssemblyFromSource(lParameters, _MyCode);

    if (lCompilerResults.Errors.Count > 0) {
        foreach (CompilerError lError in lCompilerResults.Errors) Console.WriteLine(lError.ToString());
    }
    else {
        Console.WriteLine("Compiled succesfully " + lCompilerResults.PathToAssembly);
        Console.WriteLine("Executing code now");
        MethodInfo m = lCompilerResults.CompiledAssembly.EntryPoint;
        m.Invoke(null, new object[] {});

    }
    Console.ReadLine();
} //

example output:
Compiled succesfully
Executing code now
hello world !

Expression Trees

Lambda expressions are using expression trees. The data-structure is like a tree. We are not necessarily talking about code here. Lambda expressions are not source code in the classical sense, because compilers translate expressions into code. In fact you don’t know the result, all you need to do is describing the code in an expression tree. For instance LINQ can interact between your code and a database. It can generate SQL queries. And these have nothing to do with the C# source code.

Let’s use an expression tree to generate another “Hello World” example at runtime. For this we need to implement the System.Linq.Expressions namespace. This is not really a part of reflection. I touch on the topic here to have it mentioned before we continue with Emit, which is far more on spot.

public static void Test5() {
    Expression A = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }), Expression.Constant("hello world !"));
    Expression B = Expression.Call(null, typeof(Console).GetMethod("ReadLine", new Type[] { }), null);

    Expression[] Expressions = new Expression[] { A, B };
    BlockExpression lBlockExpression = Expression.Block(Expressions);

    Action lAction = Expression.Lambda<Action>(lBlockExpression).Compile();
    lAction();
} //

Let’s build a simple calculator now. Imagine someone enters a mathematical formula in a TextBox and wants to calculate it. I have seen so many solutions on the internet and I can tell you for sure they are all far too long! In the following code you just need to add some “nice features” like pre-parsing to allow more user flexibility. The entire Math library is yours! May the 4th be with you 😉

public static void Test6() {
    string lTextBoxText = "Math.Floor(5.0  * (3.0 + 7.0) / 9.0 * Math.Exp(3.0))";
    string[] lCode = new string[] { 
        "using System;" +
        "public class MyClass {"  +
        "public static double Calc() { return (double)" + lTextBoxText + "; }" +
        "}" };


    CSharpCodeProvider lCodeProvider = new CSharpCodeProvider();
    CompilerParameters lParameters = new CompilerParameters();
    lParameters.GenerateInMemory = true;
    lParameters.GenerateExecutable = false;
    lParameters.OutputAssembly = "CalcAssembly";

    CompilerResults lCompilerResults = lCodeProvider.CompileAssemblyFromSource(lParameters, lCode);

    MethodInfo m = lCompilerResults.CompiledAssembly.GetType("MyClass").GetMethod("Calc");
    double d = (double)m.Invoke(null, null);
    Console.WriteLine("calculation result is " + d);
    Console.WriteLine("cross check result is " + (Math.Floor(5.0 * (3.0 + 7.0) / 9.0 * Math.Exp(3.0))));

    Console.ReadLine();
} //

example output:
calculation result is 111
cross check result is 111

Do you remember the post about extension methods? Unfortunately we cannot write any extension method for static classes like the .Net framework Math class. So I am going to use the string class instead. The calculator looks a little bit nicer then.

public static class MathExtension {
    public static double Formula(this string xFormula) {
        string[] lCode = new string[] { 
            "using System;" +
            "public class MyClass {"  +
            "public static double Calc() { return (double)" + xFormula + "; }" +
            "}" };


        CSharpCodeProvider lCodeProvider = new CSharpCodeProvider();
        CompilerParameters lParameters = new CompilerParameters();
        lParameters.GenerateInMemory = true;
        lParameters.GenerateExecutable = false;
        lParameters.OutputAssembly = "CalcAssembly";

        CompilerResults lCompilerResults = lCodeProvider.CompileAssemblyFromSource(lParameters, lCode);

        MethodInfo m = lCompilerResults.CompiledAssembly.GetType("MyClass").GetMethod("Calc");
        return (double)m.Invoke(null, null);
    } //        

} //

// how to call the extension method
public static void Test7() {
    string lTextBoxText = "Math.Floor(5.0  * (3.0 + 7.0) / 9.0 * Math.Exp(3.0))";
    double d = lTextBoxText.Formula();
    Console.WriteLine(d);
    Console.ReadLine();
} //

Epilogue

There are some stock market trading applications, which allow users to add their own algorithmic trading strategies. Wouldn’t it be great to enter your code in C# and use the .Net framework instead of reinventing the wheel and come up with your own scripting language that will never reach any widely recognized state of the art?

Reflection (part 3, advanced, professional), plugin

We are progressing further.

Reflection tells us all we need for plugins. Once we know the assembly we can examine it like a poor frog on the dissection table. If the dissector cannot find something, then it is not the fault of the frog. Sorry for the macabre metaphor, I could not resist my ugly thoughts.

First of all we need an assembly. In the Solution Explorer right-click your Project. The tab-menu shows (Application, Build, Build Events, Debug …). Select Application. The first entry is “Assembly name:”. You can enter your prefered assembly name here. Let’s use “TestAssembly” for our example. Now the compiler will create an assembly with the name TestAssembly.

A short test program gives you an idea where your assembly is stored and what its name is.

Assembly lAssembly = Assembly.GetCallingAssembly();
Console.WriteLine(lAssembly.Location);  // prints the full path of your assembly
Console.WriteLine(lAssembly.FullName);

You can load assemblies into applications. We are concentrating on plugins today.
In theory you can get all required information to eg. call methods or properties via reflection itself. There is no need for extra definition files. But you can also make your life easier and predefine signatures, which are used by both the application and the plugin. Of course you are implementing constraints that reduce the flexibility, but on the other hand you reduce the error-proneness and save a lot of debugging time.
So we are going to use an interface to predefine signatures. It is important that you do not copy the interface source code into both projects. You should compile the interface into a DLL-library and access these definitions from outside in the two assemblies. Otherwise the compilers generate different identifiers (see GUID) and two equal interfaces cannot be recognized as the same type.

To clearly show the independence I want you to open Visual Studio three times. Please do not create three projects in one single solution.

Visual Studio 1

Create a library project and paste the following code. We don’t need any “using” or “namespace”. Five lines of code are enough in our example.

public interface IPlugin {
    string Name { get; }
    int Born { get; }
    double DoSomething(double d, string s);
} // interface

Compile the project and move the library DLL-file to your preferred location.

Visual Studio 2

Add a reference to our interface library. (Right click on References in your Solution Explorer. Add Reference, then browse for the library file.)
We are creating the plugin now. The method Test() prints a path that you will need in the source code for the calling application (just to make your life easier).

public class MyPlugin1 : IPlugin {
    public string Name { get { return "Diana Frances"; } }
    public int Born { get { return 1961; } }
    public double DoSomething(double d, string s) { return 1.0; }
} // class

public class MyPlugin2 : IPlugin {
    public string Name { get { return "Jeanne d'Arc"; } }
    public int Born { get { return 1412; } }
    public double DoSomething(double d, string s) { return 1.0; }
} // class

public static class TestClass {
    public static void Test() {
        Assembly lPluginAssembly = Assembly.GetCallingAssembly();
        // Assembly lPluginAssembly = Assembly.Load("TestAssembly");  // alternative
        Console.WriteLine(lPluginAssembly.Location);
        Console.WriteLine(lPluginAssembly.FullName);
        Console.ReadLine();
    } //
} // class

Visual Studio 3

The projects in Visual Studio 1 and Visual Studio 2 are compiled. You can close these two programs.
Once again add a reference to our interface library. In below example code you need to replace a path by the one, which was printed out in Visual Studio 2. (in line Assembly lPluginAssembly = Assembly.LoadFile(@”xxxxxx\TestAssembly.exe”);)

static void Main(string[] args) {
    Assembly lPluginAssembly = Assembly.LoadFile(@"xxxxxx\TestAssembly.exe");
    //Assembly lPluginAssembly = Assembly.Load("TestAssembly");   => if loaded already

    var lPlugins = from t in lPluginAssembly.GetTypes()
                    where typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface
                    select t;

    foreach (Type t in lPlugins) {
        IPlugin lPlugin = Activator.CreateInstance(t) as IPlugin;
        Console.WriteLine(lPlugin.Name + " was born in " + lPlugin.Born);
        double d = lPlugin.DoSomething(2.0, "hello");
    }
    Console.ReadLine();
} // main

output example:
Diana Frances was born in 1961
Jeanne d’Arc was born in 1412

The program loaded the assembly, created instances for each class and called the properties and the method. This basically is all you need for Plugins.

Of course there are also dirty ways to invoke plugin methods. One is:

Assembly lPluginAssembly = Assembly.LoadFile(@"xxxxxx\TestAssembly.exe");
Type t = lPluginAssembly.GetType("MyNamespaceName.MyPlugin1");
MethodInfo m = t.GetMethod("DoSomething");
double d = (double)m.Invoke(Activator.CreateInstance(t), new object[] { 2.0, "hello" });                       

Reflection (part 2, advanced), attributes

In my post Reflection I covered simple reflection to follow up on generic classes.

Each application in the .Net environment is not only consisting of the program code itself, it also consists of information about the code. This information is stored in the so-called metadata. I am going to show how to read metadata attributes at runtime today.

Attributes can be applied to: Assemblies, classes, class members, constructors, delegates, enums, events, fields, interfaces, methods, modules, parameters, properties, return values and structs. You can read attributes at runtime and act accordingly. They are like information tags.

Maybe a metaphor helps to describe attributes easily. When you go shopping and buy food you can find additional information on nearly all products:
– weight
– price
– expiry date
– nutritional values (eg. vitamins, proteins, fat, sugar)
– the brand
– any information the producer wants to let you know

This is only additional data. This is not the product itself.

Attributes do not change the code execution unless actively intended by a programmer. Some attributes are read by compilers (eg. [Flags] for enum), some by applications or libraries (eg. in JSON [DataContract]).
In source codes attributes are placed in square brackets [] above the declaration that you want the attributes to apply to. For instance the often applied [Serializable] attribute of the SerializableAttribute class indicates that a type can be serialized to be stored or transmitted somewhere else.

[Serializable]
class Animal {
    public string Name { get; set; }
    public int Age { get; set; }
} 

You can use multiple attributes and some can even be applied multiple times. By convention, all attribute names end with the word Attribute to distinguish them from other items. However, you do not need to specify the Attribute suffix when using attributes in source codes. For example, you can specify DescriptionAttribute as follows:

[Serializable]
[Description("http://www.GreenPeace.com")]
class Animal {
    public string Name { get; set; }
    public int Age { get; set; }
} 

// same as the following syntax
[Serializable, Description("http://www.GreenPeace.com")]
class Animal {
    public string Name { get; set; }
    public int Age { get; set; }
} 

// same as the following syntax
[Serializable, DescriptionAttribute("http://www.GreenPeace.com")]  // [Description] == [DescriptionAttribute]
class Animal {
    public string Name { get; set; }
    public int Age { get; set; }
}

// a custom attribute that would be used multiple times
[Changes(Version=1.1, Change="Added Age")]
[Changes(Version=1.2, Change="Added Gender")]
class Animal {
    public enum eGender { male, female, dunno };

    public string Name { get; set; }
    public int Age { get; set; }
    public eGender Gender { get; set; }
} 

You can specify the target of an attribute explicitly. The following code applies all attributes to the current assembly.

[assembly: AssemblyTitle("HelloWorld")]
[assembly: AssemblyDescription("Chapter1")]
[assembly: AssemblyCompany("Hardcore Ltd.")]

The System.Attribute class is the lowest base class for all attribute classes. It has a few static methods.

[Serializable]
public class Animal {
    public string Name { get; set; }
    public int Age { get; set; }

    public static bool IsSerializable {
        get { return Attribute.IsDefined(typeof(Animal), typeof(SerializableAttribute)); }  // returns true
    } //
} // class

How to read the property of attributes?

[Description("Only cute dogs"), Serializable]
public class Dogs {
    public static void PrintProperties() {
        Attribute[] lAttributes = Attribute.GetCustomAttributes(typeof(Dogs)) as Attribute[];
        foreach (Attribute lAttribute in lAttributes) {
            Console.WriteLine(lAttribute.GetType().Name.ToString());
            if (lAttribute is DescriptionAttribute) Console.WriteLine(((DescriptionAttribute)lAttribute).Description);
        }
        Console.ReadLine();
    } //
} // class

example output:
SerializableAttribute
DescriptionAttribute
Only cute dogs

To build our own attribute we have to inherit from an existing attribute, which is at least System.Attribute. The next code example is more complex. We use multiple attributes for AnyClass.Method3() and permit this with AllowMultiple = true in our AttributeUsage. On the same line we limit the usage of our custom attribute to classes, methods and properties. The ProgrammerAttribute class does nothing else than storing the values. There is no extensive code as you might expect from real program code.
By calling typeof(AnyClass).GetMethods() we enter the method level. The flags are set the way that we receive public and private methods. The result also includes inherited methods.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
public class ProgrammerAttribute : Attribute {
    private readonly DateTime _Date;
    private readonly string _Name;
    private readonly string _Info;

    public ProgrammerAttribute(int xYear, int xMonth, int xDay, string xName, string xInfo) {
        _Name = xName;
        _Date = new DateTime(xYear, xMonth, xDay);
        _Info = xInfo;
    } // constructor

    public string Name { get { return _Name; } }
    public string Info { get { return _Info; } }
    public DateTime Date { get { return _Date; } }
} //

[Serializable]
[Programmer(2014, 1, 9, "Bastian M.K. Ohta", "added")]
public class AnyClass {
    [Programmer(2014, 1, 10, "Bastian M.K. Ohta", "bug fix: threading issue solved")]
    public double Method1(double x) { return 2 * x; }

    [Programmer(2014, 1, 12, "Bastian M.K. Ohta", "added")]
    public int Method2() { return 0; }

    [Programmer(2014, 1, 12, "Bastian M.K. Ohta", "under construction")]
    [Programmer(2014, 1, 14, "Bastian M.K. Ohta", "Programmer on vacation until Friday.")]
    private void Method3(double x) { }
} //


public static void Print(ProgrammerAttribute[] xProgrammers) {
    foreach (ProgrammerAttribute p in xProgrammers) {
        Console.WriteLine(p.Date.ToString("dd MMM yy ") + p.Name + ", " + p.Info);
    }    
} //

public static void Test() {
    ProgrammerAttribute[] lProgrammers;

    Console.WriteLine("Class level:");
    lProgrammers = Attribute.GetCustomAttributes(typeof(AnyClass), typeof(ProgrammerAttribute)) as ProgrammerAttribute[];
    Print(lProgrammers);

    Console.WriteLine(Environment.NewLine + "Methods:");
    MethodInfo[] lMethodInfos = typeof(AnyClass).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    //MethodInfo[] lMethodInfos = typeof(AnyClass).GetMethods(BindingFlags.Instance | BindingFlags.Public); // filter: only public methods
    foreach (MethodInfo m in lMethodInfos) {
        Console.WriteLine("Found method " + m.Name);
        lProgrammers = m.GetCustomAttributes(typeof(ProgrammerAttribute) , false) as ProgrammerAttribute[];
        Print(lProgrammers);
        Console.WriteLine();
    }

    Console.ReadLine();
} //

example output:
Class level:
09 Jan 14 Bastian M.K. Ohta, added

Methods:
Found method Method1
10 Jan 14 Bastian M.K. Ohta, bug fix: threading issue solved

Found method Method2
12 Jan 14 Bastian M.K. Ohta, added

Found method Method3
12 Jan 14 Bastian M.K. Ohta, am on vacation until Friday
12 Jan 14 Bastian M.K. Ohta, under construction

Found method ToString

Found method Equals

Found method GetHashCode

Found method GetType

Found method Finalize

Found method MemberwiseClone

That’s it for today. No worries, there will be many follow-ups on reflection.

Reflection (part 1, basics, advanced), types and generic types

I explained generic types yesterday. Discussing reflection is a bit early on this post. I will concentrate on some basic and slightly advanced material about generics and nullables.

Reflection is used to obtain type information at run-time.
C# offers the typeof() keyword for types and the GetType() method for objects.
The is keyword uses both and follows the pattern: object is type

AnyClass c = new AnyClass();
Type a1 = typeof(int);           // typeof(type)
Type a2 = c.GetType();           // object.GetType()
bool b = c is int;               // object is type

The is keyword returns true if an instance is in the inheritance tree. This results in a very specific behaviour:

class Animal { }
class Cat : Animal { }

public static void Generics6() {
    // easy going
    Animal lAnimal = new Animal();
    Console.WriteLine(lAnimal.GetType() == typeof(Animal)); // true 
    Console.WriteLine(lAnimal is Animal);                   // true 
    Console.WriteLine(lAnimal.GetType() == typeof(Cat));    // false

    // and now it gets tricky
    Animal lCat = new Cat();
    Console.WriteLine(lCat.GetType() == typeof(Animal)); // false !
    Console.WriteLine(lCat is Animal);                   // true ! 
    Console.WriteLine(lCat.GetType() == typeof(Cat));    // true
} //

The typeof(T) also has its own behaviour. It is does not care what true instance type it is looking at. It returns the result of the last cast operation. Here is an example program to highlight this fact:

static void Print<T>(T t, string xInfo) {
    Console.WriteLine(xInfo.PadRight(22) + "| typeof(T) " + typeof(T).Name.PadRight(7) + "| GetType(): " + t.GetType().Name.PadRight(7) + "| is Cat: " + (t is Cat).ToString().PadRight(6) + "| is Animal: " + (t is Animal));
} //

public static void Confusing() {
    Animal lAnimal = new Cat();
    Cat lCat = new Cat();

    Print(lCat, "Print(lCat)");
    Print<Cat>(lCat, "Print<Cat>(lCat)");

    Print(lAnimal, "Print(lAnimal)"); 
    Print<Animal>(lAnimal, "Print<Animal>(lAnimal)");
            
    Print<Animal>(lCat, "Print<Animal>(lCat)");
    Print((Animal)lCat, "Print((Animal)lCat)");

    //Print<Cat>(lAnimal); // compiler error    
} //

example output in a table:

Command typeof(T) GetType() Is Cat? Is Animal?
Print(lCat)

Cat

Cat

True

True

Print<Cat>(lCat)

Cat

Cat

True

True

Print(lAnimal)

Animal

Cat

True

True

Print<Animal>(lAnimal)

Animal

Cat

True

True

Print<Animal>(lCat)

Animal

Cat

True

True

Print((Animal)lCat)

Animal

Cat

True

True

Walk through the example of a generic method:

private static void Generics4<T>(T t) {
    Type lType = typeof(T);

    Console.WriteLine("Analysing variable " + t + Environment.NewLine);

    Console.WriteLine("using typeof()");
    if (lType == typeof(int)) Console.WriteLine(typeof(T).ToString() + " is an integer");
    else if (lType == typeof(string)) Console.WriteLine(typeof(T).ToString() + " is a string");

    Console.WriteLine("\nusing the \"is\" keyword");
    if (t is int) Console.WriteLine(typeof(T).ToString() + " is an integer");
    else if (t is string) Console.WriteLine(typeof(T).ToString() + " is a string");

    Console.WriteLine("\nusing GetType()");
    if (t.GetType() == typeof(int)) Console.WriteLine(typeof(T).ToString() + " is an integer");
    else if (t.GetType() == typeof(string)) Console.WriteLine(typeof(T).ToString() + " is a string");
} //

public static void Generics5() {
    Generics4(5);
    Console.WriteLine();
    Generics4("hello");
    Console.WriteLine();
    int? i = 666;
    Generics4(i);
    Console.ReadLine();
} //

Analysing variable 5

using typeof()
System.Int32 is an integer

using the “is” keyword
System.Int32 is an integer

using GetType()
System.Int32 is an integer

Analysing variable hello

using typeof()
System.String is a string

using the “is” keyword
System.String is a string

using GetType()
System.String is a string

Analysing variable 666

using typeof()

using the “is” keyword
System.Nullable`1[System.Int32] is an integer

using GetType()
System.Nullable`1[System.Int32] is an integer

The Type class offers far more information about the object we are using.

class GenericClass7<T> { public void HelloWorld() { } }
private class AnyClass { }

public static void Generics7<T>(T t) {
    Type lType = typeof(T);

    Console.WriteLine("value".PadRight(30) + t);
    Console.WriteLine("IsPublic".PadRight(30) + lType.IsPublic);
    Console.WriteLine("IsGenericParameter".PadRight(30) + lType.IsGenericParameter);
    Console.WriteLine("IsGenericType".PadRight(30) + lType.IsGenericType);
    Console.WriteLine("IsGenericTypeDefinition".PadRight(30) + lType.IsGenericTypeDefinition);
    Console.WriteLine("IsValueType".PadRight(30) + lType.IsValueType);
    Console.WriteLine("Name".PadRight(30) + lType.Name);
    Console.WriteLine("BaseTypeName".PadRight(30) + lType.BaseType.Name);
    foreach (MemberInfo lMember in lType.GetMembers()) {
        Console.WriteLine("Member".PadRight(30) + lMember.Name);
    }
    Console.WriteLine(string.Empty.PadRight(50, '-'));
} //

public static void RunTest() {
    Console.WriteLine("integer:\n");
    Generics7(1);
    Console.WriteLine("nullable integer:\n");
    Generics7(new Nullable<int>(2));
    Console.WriteLine("string:\n");
    Generics7("hello");
    Console.WriteLine("class:\n");
    Generics7(new AnyClass());
    Console.WriteLine("generic class:\n");
    Generics7(new GenericClass7<double>());

    Console.WriteLine();
} //

example output:

integer:

value 1
IsPublic True
IsGenericParameter False
IsGenericType False
IsGenericTypeDefinition False
IsValueType True
Name Int32
BaseTypeName ValueType
Member CompareTo
Member CompareTo
Member Equals
Member Equals
Member GetHashCode
Member ToString
Member ToString
Member ToString
Member ToString
Member Parse
Member Parse
Member Parse
Member Parse
Member TryParse
Member TryParse
Member GetTypeCode
Member GetType
Member MaxValue
Member MinValue
————————————————–
nullable integer:

value 2
IsPublic True
IsGenericParameter False
IsGenericType True
IsGenericTypeDefinition False
IsValueType True
Name Nullable`1
BaseTypeName ValueType
Member get_HasValue
Member get_Value
Member GetValueOrDefault
Member GetValueOrDefault
Member Equals
Member GetHashCode
Member ToString
Member op_Implicit
Member op_Explicit
Member GetType
Member .ctor
Member HasValue
Member Value
————————————————–
string:

value hello
IsPublic True
IsGenericParameter False
IsGenericType False
IsGenericTypeDefinition False
IsValueType False
Name String
BaseTypeName Object
Member Join
Member Join
Member Join
Member Join
Member Join
Member Equals
Member Equals
Member Equals
Member Equals
Member Equals
Member op_Equality
Member op_Inequality
Member get_Chars
Member CopyTo
Member ToCharArray
Member ToCharArray
Member IsNullOrEmpty
Member IsNullOrWhiteSpace
Member GetHashCode
Member get_Length
Member Split
Member Split
Member Split
Member Split
Member Split
Member Split
Member Substring
Member Substring
Member Trim
Member TrimStart
Member TrimEnd
Member IsNormalized
Member IsNormalized
Member Normalize
Member Normalize
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member CompareTo
Member CompareTo
Member CompareOrdinal
Member CompareOrdinal
Member Contains
Member EndsWith
Member EndsWith
Member EndsWith
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOfAny
Member IndexOfAny
Member IndexOfAny
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOfAny
Member LastIndexOfAny
Member LastIndexOfAny
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member PadLeft
Member PadLeft
Member PadRight
Member PadRight
Member StartsWith
Member StartsWith
Member StartsWith
Member ToLower
Member ToLower
Member ToLowerInvariant
Member ToUpper
Member ToUpper
Member ToUpperInvariant
Member ToString
Member ToString
Member Clone
Member Trim
Member Insert
Member Replace
Member Replace
Member Remove
Member Remove
Member Format
Member Format
Member Format
Member Format
Member Format
Member Copy
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Intern
Member IsInterned
Member GetTypeCode
Member GetEnumerator
Member GetType
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member Chars
Member Length
Member Empty
————————————————–
class:

value ConsoleApplication1.CGenerics+AnyClass
IsPublic False
IsGenericParameter False
IsGenericType False
IsGenericTypeDefinition False
IsValueType False
Name AnyClass
BaseTypeName Object
Member ToString
Member Equals
Member GetHashCode
Member GetType
Member .ctor
————————————————–
generic class:

value ConsoleApplication1.CGenerics+GenericClass7`1[System.Double]
IsPublic False
IsGenericParameter False
IsGenericType True
IsGenericTypeDefinition False
IsValueType False
Name GenericClass7`1
BaseTypeName Object
Member HelloWorld
Member ToString
Member Equals
Member GetHashCode
Member GetType
Member .ctor
————————————————–

I guess there could be hundreds of posts just about reflection. This short explanation should be enough for today. Basically we would start digging ourselves deep into the System.Reflection.Emit namespace. We will touch this topic again when appropriate.