class Program
{
  delegate int IntFunc (int x);

  static int Square (int x) { return x * x; }       // metoda statyczna
  int        Cube   (int x) { return x * x * x; }   // metoda statyczna

  static void Main()
  {
    Delegate staticD = Delegate.CreateDelegate
      (typeof (IntFunc), typeof (Program), "Square");

    Delegate instanceD = Delegate.CreateDelegate
      (typeof (IntFunc), new Program(), "Cube");

    Console.WriteLine (staticD.DynamicInvoke (3));      // 9
    Console.WriteLine (instanceD.DynamicInvoke (3));    // 27
  }
}

------------------------------------------------------------------------------
IntFunc f = (IntFunc) staticD;
Console.WriteLine (f(3));         // 9 (ale znacznie szybciej!)

------------------------------------------------------------------------------

class Program
{
  static void Main()
  {
    // MethodInfo jest podklasą MemberInfo; zob. rysunek 19.1.

    MethodInfo test = typeof (Program).GetMethod ("ToString");
    MethodInfo obj  = typeof (object) .GetMethod ("ToString");

    Console.WriteLine (test.DeclaringType);      // System.Object
    Console.WriteLine (obj.DeclaringType);       // System.Object

    Console.WriteLine (test.ReflectedType);      // Program
    Console.WriteLine (obj.ReflectedType);       // System.Object

    Console.WriteLine (test == obj);             // False
  }
}

------------------------------------------------------------------------------
Console.WriteLine (test.MethodHandle == obj.MethodHandle);    // True

Console.WriteLine (test.MetadataToken == obj.MetadataToken    // True
                   && test.Module == obj.Module);

------------------------------------------------------------------------------

PropertyInfo open   = typeof (IEnumerator<>)   .GetProperty ("Current");
PropertyInfo closed = typeof (IEnumerator<int>).GetProperty ("Current");

Console.WriteLine (open);    // T Current
Console.WriteLine (closed);  // Int32 Current

Console.WriteLine (open  .PropertyType.IsGenericParameter);  // True
Console.WriteLine (closed.PropertyType.IsGenericParameter);  // False

------------------------------------------------------------------------------
PropertyInfo open   = typeof (List<>)   .GetProperty ("Count");
PropertyInfo closed = typeof (List<int>).GetProperty ("Count");

Console.WriteLine (open);      // Int32 Count
Console.WriteLine (closed);    // Int32 Count

Console.WriteLine (open == closed);   // False

Console.WriteLine (open  .DeclaringType.IsGenericTypeDefinition); // True
Console.WriteLine (closed.DeclaringType.IsGenericTypeDefinition); // False

------------------------------------------------------------------------------

Type type = typeof (string);
Type[] parameterTypes = { typeof (int) };
MethodInfo method = type.GetMethod ("Substring", parameterTypes);

object[] arguments = { 2 };
object returnValue = method.Invoke ("stempel", arguments);
Console.WriteLine (returnValue);                           // "empel"

------------------------------------------------------------------------------
ParameterInfo[] paramList = method.GetParameters();
foreach (ParameterInfo x in paramList)
{
  Console.WriteLine (x.Name);                 // startIndex
  Console.WriteLine (x.ParameterType);        // System.Int32
}

------------------------------------------------------------------------------

object[] args = { "23", 0 };
Type[] argTypes = { typeof (string), typeof (int).MakeByRefType() };
MethodInfo tryParse = typeof (int).GetMethod ("TryParse", argTypes);
bool successfulParse = (bool) tryParse.Invoke (null, args);

Console.WriteLine (successfulParse + " " + args[1]);       // True 23

------------------------------------------------------------------------------

delegate string StringToString (string s);

static void Main()
{
  MethodInfo trimMethod = typeof (string).GetMethod ("Trim", new Type[0]);
  var trim = (StringToString) Delegate.CreateDelegate
                                    (typeof (StringToString), trimMethod);
  for (int i = 0; i < 1000000; i++)
    trim ("test");
}

------------------------------------------------------------------------------

class Walnut
{
  private bool cracked;
  public void Crack() { cracked = true; }

  public override string ToString() { return cracked.ToString(); }
}

------------------------------------------------------------------------------
Type t = typeof (Walnut);
Walnut w = new Walnut();
w.Crack();
FieldInfo f = t.GetField ("cracked", BindingFlags.NonPublic |
                                     BindingFlags.Instance);
f.SetValue (w, false);
Console.WriteLine (w);         // False

------------------------------------------------------------------------------

class Program
{
  public static T Echo<T> (T x) { return x; }

  static void Main()
  {
    MethodInfo echo = typeof (Program).GetMethod ("Echo");
    Console.WriteLine (echo.IsGenericMethodDefinition);    // True
    echo.Invoke (null, new object[] { 123 } );             // Wyjątek
  }
}

------------------------------------------------------------------------------
MethodInfo echo = typeof (Program).GetMethod ("Echo");
MethodInfo intEcho = echo.MakeGenericMethod (typeof (int));
Console.WriteLine (intEcho.IsGenericMethodDefinition);            // False
Console.WriteLine (intEcho.Invoke (null, new object[] { 3 } ));   // 3

------------------------------------------------------------------------------

public static string ToStringEx (object value)
{
  if (value == null) return "<null>";
  if (value.GetType().IsPrimitive) return value.ToString();

  StringBuilder sb = new StringBuilder();

  if (value is IList)
    sb.Append ("Lista " + ((IList)value).Count + " elementów: ");

  Type closedIGrouping = value.GetType().GetInterfaces()
    .Where (t => t.IsGenericType &&
                 t.GetGenericTypeDefinition() == typeof (IGrouping<,>))
    .FirstOrDefault();

  if (closedIGrouping != null)   // Wywołanie właściwości dla IGrouping<,>
  {
    PropertyInfo pi = closedIGrouping.GetProperty ("Key");
    object key = pi.GetValue (value, null);
    sb.Append ("Grupowanie z kluczem=" + key + ": ");
  }

  if (value is IEnumerable)
    foreach (object element in ((IEnumerable)value))
      sb.Append (ToStringEx (element) + " ");

  if (sb.Length == 0) sb.Append (value.ToString());

  return "\r\n" + sb.ToString();
}

------------------------------------------------------------------------------

[AttributeUsage (AttributeTargets.Method)]
public sealed class TestAttribute : Attribute
{
  public int     Repetitions;
  public string  FailureMessage;

  public TestAttribute () : this (1)     {}
  public TestAttribute (int repetitions) { Repetitions = repetitions; }
}

------------------------------------------------------------------------------

class Foo
{
  [Test]
  public void Method1() { ... }
  
  [Test(20)]
  public void Method2() { ... }
  
  [Test(20, FailureMessage="Czas na debugowanie!")]
  public void Method3() { ... }
}

------------------------------------------------------------------------------

foreach (MethodInfo mi in typeof (Foo).GetMethods())
{
  TestAttribute att = (TestAttribute) Attribute.GetCustomAttribute
    (mi, typeof (TestAttribute));
  
  if (att != null)
    Console.WriteLine ("Metoda {0} zostanie przetestowana; powt={1}; wiad={2}",
                        mi.Name, att.Repetitions, att.FailureMessage);
}

------------------------------------------------------------------------------
foreach (MethodInfo mi in typeof (Foo).GetMethods())
{
  TestAttribute att = (TestAttribute) Attribute.GetCustomAttribute
    (mi, typeof (TestAttribute));

  if (att != null)
    for (int i = 0; i < att.Repetitions; i++)
      try
      {
        mi.Invoke (new Foo(), null);    // wywołanie metody bez argumentów
      }
      catch (Exception ex)       // otoczenie wyjątku za pomocą att.FailureMessage
      {
        throw new Exception ("Błąd: " + att.FailureMessage, ex);
      }
}

------------------------------------------------------------------------------
[Serializable, Obsolete]
class Test
{
  static void Main()
  {
    object[] atts = Attribute.GetCustomAttributes (typeof (Test));
    foreach (object att in atts) Console.WriteLine (att);
  }
}

------------------------------------------------------------------------------

IList<CustomAttributeData> atts = CustomAttributeData.GetCustomAttributes
                                  (myReflectionOnlyType);
foreach (CustomAttributeData att in atts)
{
  Console.Write (att.GetType());               // typ atrybutu

  Console.WriteLine (" " + att.Constructor);   // obiekt ConstructorInfo

  foreach (CustomAttributeTypedArgument arg in att.ConstructorArguments)
    Console.WriteLine ("  " +arg.ArgumentType + "=" + arg.Value);

  foreach (CustomAttributeNamedArgument arg in att.NamedArguments)
    Console.WriteLine ("  " + arg.MemberInfo.Name + "=" + arg.TypedValue);
}

------------------------------------------------------------------------------

ResolveEventHandler handler = (object sender, ResolveEventArgs args)
                            => Assembly.ReflectionOnlyLoad (args.Name);

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += handler;

// refleksje atrybutów...

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= handler;

------------------------------------------------------------------------------

public class Test
{
  static void Main()
  {
    var dynMeth = new DynamicMethod ("Foo", null, null, typeof (Test));
    ILGenerator gen = dynMeth.GetILGenerator(); 
    gen.EmitWriteLine ("Witaj, świecie");
    gen.Emit (OpCodes.Ret);
    dynMeth.Invoke (null, null);                    // Witaj, świecie
  }
}

------------------------------------------------------------------------------

public class Test
{
  static void Main()
  {
    var dynMeth = new DynamicMethod ("Foo", null, null, typeof (Test));
    ILGenerator gen = dynMeth.GetILGenerator();

    MethodInfo privateMethod = typeof(Test).GetMethod ("HelloWorld",
     BindingFlags.Static | BindingFlags.NonPublic);

    gen.Emit (OpCodes.Call, privateMethod);     // wywołanie HelloWorld
    gen.Emit (OpCodes.Ret);

    dynMeth.Invoke (null, null);                // Witaj, świecie
  }

  static void HelloWorld()       // metoda prywatna, ale możemy ją wywołać
  {
    Console.WriteLine ("Witaj, świecie");
  }
}

------------------------------------------------------------------------------

var dynMeth = new DynamicMethod ("Foo", null, null, typeof(void));
ILGenerator gen = dynMeth.GetILGenerator(); 
MethodInfo writeLineInt = typeof (Console).GetMethod ("WriteLine",
                                        new Type[] { typeof (int) });

// kody operacji Ldc* ładują literały numeryczny e różnych typów i rozmiarów.

gen.Emit (OpCodes.Ldc_I4, 123);        // wstawienie 4-bajtowej liczby całkowitej na stos
gen.Emit (OpCodes.Call, writeLineInt);

gen.Emit (OpCodes.Ret);
dynMeth.Invoke (null, null);           // 123

------------------------------------------------------------------------------

gen.Emit (OpCodes.Ldc_I4, 2);           // wstawienie 4-bajtowej liczby całkowitej, wartość=2
gen.Emit (OpCodes.Ldc_I4, 2);           // wstawienie 4-bajtowej liczby całkowitej, wartość=2
gen.Emit (OpCodes.Add);                 // dodanie do siebie liczb
gen.Emit (OpCodes.Call, writeLineInt);

------------------------------------------------------------------------------

gen.Emit (OpCodes.Ldc_I4, 10);
gen.Emit (OpCodes.Ldc_I4, 2);
gen.Emit (OpCodes.Div);
gen.Emit (OpCodes.Ldc_I4, 1);
gen.Emit (OpCodes.Add);
gen.Emit (OpCodes.Call, writeLineInt);

------------------------------------------------------------------------------

gen.Emit (OpCodes.Ldc_I4, 1);
gen.Emit (OpCodes.Ldc_I4, 10);
gen.Emit (OpCodes.Ldc_I4, 2);
gen.Emit (OpCodes.Div);
gen.Emit (OpCodes.Add);
gen.Emit (OpCodes.Call, writeLineInt);

------------------------------------------------------------------------------

DynamicMethod dynMeth = new DynamicMethod ("Foo",
  typeof (int),                              // typ zwracany = int
  new[] { typeof (int), typeof (int) },      // typy parametrów = int, int
  typeof (void));

ILGenerator gen = dynMeth.GetILGenerator();

gen.Emit (OpCodes.Ldarg_0);    // wstawienie pierwszego argumentu na stos ewaluacji
gen.Emit (OpCodes.Ldarg_1);    // wstawienie drugiego argumentu na stos ewaluacji
gen.Emit (OpCodes.Add);        // dodanie ich do siebie (wynik na stosie)
gen.Emit (OpCodes.Ret);        // zwrócenie dla stosu zawierającego jedną wartość

int result = (int) dynMeth.Invoke (null, new object[] { 3, 4 } );   // 7

------------------------------------------------------------------------------

var dynMeth = new DynamicMethod ("Test", null, null, typeof (void));
ILGenerator gen = dynMeth.GetILGenerator();

LocalBuilder localX = gen.DeclareLocal (typeof (int));    // deklaracja x
LocalBuilder localY = gen.DeclareLocal (typeof (int));    // deklaracja y

gen.Emit (OpCodes.Ldc_I4, 6);       // wstawienie literału 6 na stos ewaluacji
gen.Emit (OpCodes.Stloc, localX);   // przechowanie w localX
gen.Emit (OpCodes.Ldc_I4, 7);       // wstawienie literału 7 na stos ewalauacji
gen.Emit (OpCodes.Stloc, localY);   // przechowanie w localY

gen.Emit (OpCodes.Ldloc, localX);   // wstawienie localX na stos ewaluacji
gen.Emit (OpCodes.Ldloc, localY);   // wstawienie localY na stos ewaluacji
gen.Emit (OpCodes.Mul);             // przemnożenie wartości
gen.Emit (OpCodes.Stloc, localX);   // przechowanie wyniku w localX

gen.EmitWriteLine (localX);         // wyświetlenie wartości localX
gen.Emit (OpCodes.Ret);

dynMeth.Invoke (null, null);         // 42

------------------------------------------------------------------------------

ILGenerator gen = ...

Label startLoop = gen.DefineLabel();                  // deklarowanie etykiet
Label endLoop = gen.DefineLabel();

LocalBuilder x = gen.DeclareLocal (typeof (int));     // int x
gen.Emit (OpCodes.Ldc_I4, 5);                         //
gen.Emit (OpCodes.Stloc, x);                          // x = 5

gen.MarkLabel (startLoop); 
  gen.Emit (OpCodes.Ldc_I4, 10);          // wstawienie 10 na stos ewaluacji
  gen.Emit (OpCodes.Ldloc, x);            // załadowanie x na stos ewaluacji
    
  gen.Emit (OpCodes.Blt, endLoop);        // if (x > 10) goto endLoop
    
  gen.EmitWriteLine (x);                  // Console.WriteLine (x)
    
  gen.Emit (OpCodes.Ldloc, x);            // wstawienie x na stos ewaluacji
  gen.Emit (OpCodes.Ldc_I4, 1);           // wstawienie 1 na stos
  gen.Emit (OpCodes.Add);                 // dodanie ich do siebie
  gen.Emit (OpCodes.Stloc, x);            // zapisanie wyniku w zmiennej x
   
  gen.Emit (OpCodes.Br, startLoop);       // powrót do początku pętli
gen.MarkLabel (endLoop);

gen.Emit (OpCodes.Ret);

------------------------------------------------------------------------------

var dynMeth = new DynamicMethod ("Test", null, null, typeof (void));
ILGenerator gen = dynMeth.GetILGenerator();

ConstructorInfo ci = typeof (StringBuilder).GetConstructor (new Type[0]);

gen.Emit (OpCodes.Newobj, ci);

gen.Emit (OpCodes.Callvirt, typeof (StringBuilder)
                            .GetProperty ("MaxCapacity").GetGetMethod());

gen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine",
                                         new[] { typeof (int) } ));
gen.Emit (OpCodes.Ret);
dynMeth.Invoke (null, null);              // 2147483647

------------------------------------------------------------------------------

// wywołamy:   new StringBuilder ("Witaj", 1000)

ConstructorInfo ci = typeof (StringBuilder).GetConstructor (
                     new[] { typeof (string), typeof (int) } );

gen.Emit (OpCodes.Ldstr, "Witaj");   // wstawienie ciągu znaków na stos ewaluacji
gen.Emit (OpCodes.Ldc_I4, 1000);     // wstawienie liczby całkowitej na stos ewaluacji
gen.Emit (OpCodes.Newobj, ci);       // stworzenie obiektu StringBuilder

Type[] strT = { typeof (string) };
gen.Emit (OpCodes.Ldstr, ", świecie!");
gen.Emit (OpCodes.Call, typeof (StringBuilder).GetMethod ("Append", strT));
gen.Emit (OpCodes.Callvirt, typeof (object).GetMethod ("ToString"));
gen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", strT));
gen.Emit (OpCodes.Ret);
dynMeth.Invoke (null, null);        // Witaj, świecie!  

------------------------------------------------------------------------------

MethodInfo getMessageProp = typeof (NotSupportedException)
                            .GetProperty ("Message").GetGetMethod();

MethodInfo writeLineString = typeof (Console).GetMethod ("WriteLine",
                                             new[] { typeof (object) } );
gen.BeginExceptionBlock();
  ConstructorInfo ci = typeof (NotSupportedException).GetConstructor (
                                                        new Type[0] );
  gen.Emit (OpCodes.Newobj, ci);
  gen.Emit (OpCodes.Throw);
gen.BeginCatchBlock (typeof (NotSupportedException));
  gen.Emit (OpCodes.Callvirt, getMessageProp);
  gen.Emit (OpCodes.Call, writeLineString);
gen.BeginFinallyBlock();
  gen.EmitWriteLine ("Finally");
gen.EndExceptionBlock();

------------------------------------------------------------------------------

AppDomain appDomain = AppDomain.CurrentDomain;

AssemblyName aname = new AssemblyName ("MyDynamicAssembly");

AssemblyBuilder assemBuilder =
  appDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);

ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule ("DynModule");

TypeBuilder tb = modBuilder.DefineType ("Widget", TypeAttributes.Public);

MethodBuilder methBuilder = tb.DefineMethod ("SayHello",
                                             MethodAttributes.Public,
                                             null, null);
ILGenerator gen = methBuilder.GetILGenerator();
gen.EmitWriteLine ("Witaj, świecie");
gen.Emit (OpCodes.Ret);  

Type t = tb.CreateType();

object o = Activator.CreateInstance (t);
t.GetMethod ("SayHello").Invoke (o, null);        // Witaj, świecie

------------------------------------------------------------------------------

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName aname = new AssemblyName ("MyEmissions");
aname.Version = new Version (2, 13, 0, 1);

AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly (
  aname, AssemblyBuilderAccess.RunAndSave);

ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule (
  "MainModule", "MyEmissions.dll");

// stworzenie typów tak, jak robiliśmy to wcześniej
// ...

assemBuilder.Save ("MyEmissions.dll");

------------------------------------------------------------------------------

AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName ("MyEmissions");

AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly (
  aname, AssemblyBuilderAccess.RunAndSave);

ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule (
  "MainModule", "MyEmissions.dll");

TypeBuilder tb = modBuilder.DefineType ("Widget", TypeAttributes.Public);

------------------------------------------------------------------------------

MethodBuilder mb = tb.DefineMethod ("SquareRoot",
  MethodAttributes.Static | MethodAttributes.Public,
  CallingConventions.Standard,
  typeof (double),                     // typ wartości zwracanej 
  new[]  { typeof (double) } );        // typy parametrów

mb.DefineParameter (1, ParameterAttributes.None, "value");  // przypisanie nazwy

ILGenerator gen = mb.GetILGenerator();
gen.Emit (OpCodes.Ldarg_0);                                // załadowanie pierwszego argumentu
gen.Emit (OpCodes.Call, typeof(Math).GetMethod ("Sqrt"));
gen.Emit (OpCodes.Ret);

Type realType = tb.CreateType();
double x = (double) tb.GetMethod ("SquareRoot").Invoke (null,
                                                new object[] { 10.0 });
Console.WriteLine (x);   // 3.16227766016838

------------------------------------------------------------------------------

MethodBuilder mb = tb.DefineMethod ("SquareRoot",
  MethodAttributes.Static | MethodAttributes.Public,
  CallingConventions.Standard,
  null,
  new Type[] { typeof (double).MakeByRefType() } );

mb.DefineParameter (1, ParameterAttributes.None, "value");

ILGenerator gen = mb.GetILGenerator();
gen.Emit (OpCodes.Ldarg_0);
gen.Emit (OpCodes.Ldarg_0);
gen.Emit (OpCodes.Ldind_R8);
gen.Emit (OpCodes.Call, typeof (Math).GetMethod ("Sqrt"));
gen.Emit (OpCodes.Stind_R8);
gen.Emit (OpCodes.Ret);

Type realType = tb.CreateType();
object[] args = { 10.0 };
tb.GetMethod ("SquareRoot").Invoke (null, args);
Console.WriteLine (args[0]);                     // 3.16227766016838

------------------------------------------------------------------------------

FieldBuilder field = tb.DefineField ("_text", typeof (string),
                                      FieldAttributes.Private);
PropertyBuilder prop = tb.DefineProperty (
                         "Text",                      // nazwa właściwości
                         PropertyAttributes.None,      
                         typeof (string),             // typ właściwości
                         new Type[0]);                // typy indeksera

MethodBuilder getter = tb.DefineMethod (
  "get_Text",                                         // nazwa metody
  MethodAttributes.Public | MethodAttributes.SpecialName,
  typeof (string),                                    // typ zwracany
  new Type[0]);                                       // typy parametrów

ILGenerator getGen = getter.GetILGenerator();
getGen.Emit (OpCodes.Ldarg_0);        // wstawienie "this" na stos ewaluacji
getGen.Emit (OpCodes.Ldfld, field);   // wstawienie wartości pola na stos ewaluacji
getGen.Emit (OpCodes.Ret);            // return

MethodBuilder setter = tb.DefineMethod (
  "set_Text",
  MethodAttributes.Assembly | MethodAttributes.SpecialName,
  null,                                                 // typ zwracania
  new Type[] { typeof (string) } );                     // typy parametrów

ILGenerator setGen = setter.GetILGenerator();
setGen.Emit (OpCodes.Ldarg_0);          // wstawienie "this" na stos ewaluacji
setGen.Emit (OpCodes.Ldarg_1);          // wstawienie drugiego argumentu, czyli wartości
setGen.Emit (OpCodes.Stfld, field);     // zapisanie wartości w polu
setGen.Emit (OpCodes.Ret);              // return

prop.SetGetMethod (getter);             // podpięcie metody get do właściwości
prop.SetSetMethod (setter);             // podpięcie metody set do właściwości

------------------------------------------------------------------------------
Type t = tb.CreateType();
object o = Activator.CreateInstance (t);
t.GetProperty ("Text").SetValue (o, "Good emissions!", new object[0]);
string text = (string) t.GetProperty ("Text").GetValue (o, null);

Console.WriteLine (text);             // dobre emisje!

------------------------------------------------------------------------------

FieldBuilder field = tb.DefineField ("_capacity", typeof (int),
                                      FieldAttributes.Private);
ConstructorBuilder c = tb.DefineConstructor (
  MethodAttributes.Public,
  CallingConventions.Standard,
  new Type[0]);                  // parametry konstruktora

ILGenerator gen = c.GetILGenerator();

gen.Emit (OpCodes.Ldarg_0);             // wstawienie "this" na stos ewaluacji
gen.Emit (OpCodes.Ldc_I4, 4000);        // wstawienie 4000 na stos ewaluacji
gen.Emit (OpCodes.Stfld, field);        // zapisanie wartości w polu
gen.Emit (OpCodes.Ret);

------------------------------------------------------------------------------

gen.Emit (OpCodes.Ldarg_0);
ConstructorInfo baseConstr = typeof (B).GetConstructor (new Type[0]);
gen.Emit (OpCodes.Call, baseConstr);

------------------------------------------------------------------------------

Type attType = typeof (XmlElementAttribute);

ConstructorInfo attConstructor = attType.GetConstructor (
  new Type[] { typeof (string) } );

var att = new CustomAttributeBuilder (
  attConstructor,                         // konstruktor
  new object[] { "FirstName" },           // argumenty konstruktora
  new PropertyInfo[]
  {
      attType.GetProperty ("Namespace"),  // właściwości
      attType.GetProperty ("Order")
  },
  new object[] { "http://test/", 3 }      // wartości właściwości
);

myFieldBuilder.SetCustomAttribute (att);
// lub propBuilder.SetCustomAttribute (att);
// lub typeBuilder.SetCustomAttribute (att);  itd.

------------------------------------------------------------------------------

AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName ("MyEmissions");

AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly (
  aname, AssemblyBuilderAccess.RunAndSave);

ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule (
  "MainModule", "MyEmissions.dll");

------------------------------------------------------------------------------

TypeBuilder tb = modBuilder.DefineType ("Widget", TypeAttributes.Public);

MethodBuilder mb = tb.DefineMethod ("Echo", MethodAttributes.Public |
                                            MethodAttributes.Static);
GenericTypeParameterBuilder[] genericParams 
  = mb.DefineGenericParameters ("T");

mb.SetSignature (genericParams[0],     // typ zwracany 
                 null, null,
                 genericParams,        // typy parametrów 
                 null, null);

mb.DefineParameter (1, ParameterAttributes.None, "value");   // opcjonalnie

ILGenerator gen = mb.GetILGenerator();
gen.Emit (OpCodes.Ldarg_1);
gen.Emit (OpCodes.Ret);

------------------------------------------------------------------------------

TypeBuilder tb = modBuilder.DefineType ("Widget", TypeAttributes.Public);

GenericTypeParameterBuilder[] genericParams
  = tb.DefineGenericParameters ("T");

tb.DefineField ("Value", genericParams[0], FieldAttributes.Public);

------------------------------------------------------------------------------

TypeBuilder tb = modBuilder.DefineType ("Widget", TypeAttributes.Public);

MethodBuilder mb = tb.DefineMethod ("Test", MethodAttributes.Public |
                                            MethodAttributes.Static);
ILGenerator gen = mb.GetILGenerator();

Type variableType = typeof (List<>).MakeGenericType (tb);

ConstructorInfo open = typeof (List<>).GetConstructor (new Type[0]);
ConstructorInfo ci   = TypeBuilder.GetConstructor (variableType, open);

LocalBuilder listVar = gen.DeclareLocal (variableType);
gen.Emit (OpCodes.Newobj, ci);
gen.Emit (OpCodes.Stloc, listVar);
gen.Emit (OpCodes.Ret);

------------------------------------------------------------------------------

var publicAtt = FieldAttributes.Public;

TypeBuilder aBuilder = modBuilder.DefineType ("A");
TypeBuilder bBuilder = modBuilder.DefineType ("B");

FieldBuilder bee = aBuilder.DefineField ("Bee", bBuilder, publicAtt);
FieldBuilder aye = bBuilder.DefineField ("Aye", aBuilder, publicAtt);

Type realA = aBuilder.CreateType();
Type realB = bBuilder.CreateType();

------------------------------------------------------------------------------
var pub = FieldAttributes.Public;

TypeBuilder aBuilder = modBuilder.DefineType ("A");
TypeBuilder bBuilder = modBuilder.DefineType ("B");

aBuilder.DefineField ("Bee", typeof(S<>).MakeGenericType (bBuilder), pub);
bBuilder.DefineField ("Aye", typeof(S<>).MakeGenericType (aBuilder), pub);

------------------------------------------------------------------------------
TypeBuilder[] uncreatedTypes = { aBuilder, bBuilder };

ResolveEventHandler handler = delegate (object o, ResolveEventArgs args)
{
  var type = uncreatedTypes.FirstOrDefault (t => t.FullName == args.Name);
  return type == null ? null : type.CreateType().Assembly;
};

AppDomain.CurrentDomain.TypeResolve += handler;

Type realA = aBuilder.CreateType();
Type realB = bBuilder.CreateType();

AppDomain.CurrentDomain.TypeResolve -= handler;

------------------------------------------------------------------------------

using System;
using System.Text;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Xml;

class Disassembler
{
  public static string Disassemble (MethodBase method)
  {
    return new Disassembler (method).Dis ();
  }

  static Dictionary<short, OpCode> _opcodes = new Dictionary<short, OpCode> ();
  static Disassembler ()
  {
    foreach (FieldInfo fi in typeof (OpCodes).GetFields
                             (BindingFlags.Public | BindingFlags.Static))
      if (typeof (OpCode).IsAssignableFrom (fi.FieldType))
      {
        OpCode code = (OpCode)fi.GetValue (null);
        if (code.OpCodeType != OpCodeType.Nternal)
          _opcodes.Add (code.Value, code);
      }
  }

  StringBuilder _output;
  Module _module;
  byte[] _il;
  int _pos;

  Disassembler (MethodBase method)
  {
    _module = method.DeclaringType.Module;
    _il = method.GetMethodBody ().GetILAsByteArray ();
  }

  string Dis ()
  {
    _output = new StringBuilder ();
    while (_pos < _il.Length) DisassembleNextInstruction ();
    return _output.ToString ();
  }

  void DisassembleNextInstruction ()
  {
    int opStart = _pos;

    OpCode code = ReadOpCode ();
    string operand = ReadOperand (code);

    _output.AppendFormat ("IL_{0:X4}:  {1,-12} {2}",
                           opStart, code.Name, operand);
    _output.AppendLine ();
  }

  string ReadOperand (OpCode c)
  {
    int operandLength =
      c.OperandType == OperandType.InlineNone
        ? 0 :
      c.OperandType == OperandType.ShortInlineBrTarget
      || c.OperandType == OperandType.ShortInlineI
      || c.OperandType == OperandType.ShortInlineVar
        ? 1 :
      c.OperandType == OperandType.InlineVar
        ? 2 :
      c.OperandType == OperandType.InlineI8
      || c.OperandType == OperandType.InlineR
        ? 8 :
      c.OperandType == OperandType.InlineSwitch
        ? 4 * (BitConverter.ToInt32 (_il, _pos) + 1)
        : 4;
    
    if (_pos + operandLength > _il.Length)
      throw new Exception ("Nieoczekiwany koniec IL");

    string result = FormatOperand (c, operandLength);
    if (result == null)
    {
      result = "";
      for (int i = 0; i < operandLength; i++)
        result += _il[_pos + i].ToString ("X2") + " ";
    }
    _pos += operandLength;
    return result;
  }  

  OpCode ReadOpCode ()
  {
    byte byteCode = _il[_pos++];
    if (_opcodes.ContainsKey (byteCode)) return _opcodes[byteCode];

    if (_pos == _il.Length)
      throw new Exception ("Nie można znaleźć kodu operacji  " + byteCode);

    short shortCode = (short)(byteCode * 256 + _il[_pos++]);

    if (!_opcodes.ContainsKey (shortCode))
      throw new Exception ("Cannot find opcodeNie można znaleźć kodu operacji " + shortCode);

    return _opcodes[shortCode];
  }

  string FormatOperand (OpCode c, int operandLength)
  {
    if (operandLength == 0) return "";

    if (operandLength == 4)
      return Get4ByteOperand (c);
    else if (c.OperandType == OperandType.ShortInlineBrTarget)
      return GetShortRelativeTarget();
    else if (c.OperandType == OperandType.InlineSwitch)
      return GetSwitchTarget (operandLength);
    else
      return null;
  }

  string Get4ByteOperand (OpCode c)
  {
    int intOp = BitConverter.ToInt32 (_il, _pos);
   
    switch (c.OperandType)
    {
      case OperandType.InlineTok:
      case OperandType.InlineMethod:
      case OperandType.InlineField:
      case OperandType.InlineType:
        MemberInfo mi;
        try   { mi = _module.ResolveMember (intOp); }
        catch { return null; }
        if (mi == null) return null;

        if (mi.ReflectedType != null)
          return mi.ReflectedType.FullName + "." + mi.Name;
        else if (mi is Type)
          return ((Type)mi).FullName;
        else
          return mi.Name;

      case OperandType.InlineString:
        string s = _module.ResolveString (intOp);
        if (s != null) s = "\"" + s + "\"";
        return s;

      case OperandType.InlineBrTarget:
        return "IL_" + (_pos + intOp + 4).ToString ("X4");

      default:
        return null;
    }
  }

  string GetShortRelativeTarget()
  {
    return "IL_" + (_pos + (sbyte)_il[_pos] + 1).ToString ("X4");
  }

  string GetSwitchTarget (int operandLength)
  {
    int targetCount = BitConverter.ToInt32 (_il, _pos);
    string [] targets = new string [targetCount];
    for (int i = 0; i < targetCount; i++)
    {
      int ilTarget = BitConverter.ToInt32 (_il, _pos + (i + 1) * 4);
      targets [i] = "IL_" + (_pos + ilTarget + operandLength).ToString ("X4");
    }
    return "(" + string.Join (", ", targets) + ")";
  }
}
