/// <summary>
    /// Constructs a new dynamic entity type from the specified DynamicTypeInfo.
    /// </summary>
    /// <param name="info">An DynamicTypeInfo instance</param>
    /// <returns></returns>
    /// <exception cref="ArgumentException">Thrown if the dynamic type key name is already defined.</exception>
    public static Type CreateType(DynamicTypeInfo info) {
      if (info == null) {
        throw new ArgumentNullException("info");
      }

      AssemblyBuilder asmBuilder = BuildAssembly(info);
      ModuleBuilder modBuilder = BuildModule(info, asmBuilder);
      TypeBuilder typBuilder = BuildType(info, modBuilder);
      GenericTypeParameterBuilder[] parameterBuilders = BuildGenericParameters(info, typBuilder);

      // Build the fields
      var fieldBuilders = BuildFields(info, typBuilder, parameterBuilders).ToList();

      // Build an empty (parameterless) ctor
      BuildEmptyCtor(info, typBuilder);
      // Build a ctor that includes all properties.
      BuildCtor(info, typBuilder, fieldBuilders, parameterBuilders);
      

      // Build Properties
      BuildProperties(info, typBuilder, fieldBuilders, parameterBuilders);

      // BuildEqualsMethod(info, typBuilder, fieldBuilders);
      // BuildGetHashCodeMethod(info, typBuilder, fieldBuilders);

      var openGenericType = typBuilder.CreateType();
      var returnType = openGenericType.MakeGenericType(info.PropertyTypes.ToArray());
      //OnDynamicEntityTypeCreated(new DynamicEntityTypeCreatedEventArgs(returnType));
      if (info.DynamicTypeShouldSave) {
#if !SILVERLIGHT
        asmBuilder.Save(asmBuilder.GetName().Name + ".dll");
#endif
      }

      return returnType;

    }
    //// This method does not work for Silverlight. It executes but the call to Equals fails with a VerificationException at runtime
    //private static void BuildEqualsMethod(DynamicTypeInfo info, TypeBuilder typBuilder, List<FieldBuilder> fields) {
    //  var methodBuilder = typBuilder.DefineMethod("Equals",
    //      MethodAttributes.Public | MethodAttributes.ReuseSlot |
    //      MethodAttributes.Virtual | MethodAttributes.HideBySig,
    //      typeof(bool), new Type[] { typeof(object) });
    //  var generator = methodBuilder.GetILGenerator();
    //  LocalBuilder other = generator.DeclareLocal(typBuilder);
    //  Label next = generator.DefineLabel();
    //  generator.Emit(OpCodes.Ldarg_1);
    //  generator.Emit(OpCodes.Isinst, typBuilder);
    //  generator.Emit(OpCodes.Stloc, other);
    //  generator.Emit(OpCodes.Ldloc, other);
    //  generator.Emit(OpCodes.Brtrue_S, next);
    //  generator.Emit(OpCodes.Ldc_I4_0);
    //  generator.Emit(OpCodes.Ret);
    //  generator.MarkLabel(next);

    //  var tuples = info.PropertyTypes.Zip(fields, (t, f) => Tuple.Create(t, f));
    //  foreach (var tuple in tuples) {
    //    // can't use field.FieldType because it returns an unresolved generic type.
    //    Type fieldType = tuple.Item1; // field.FieldType;
    //    FieldBuilder field = tuple.Item2;

    //    Type ct = typeof(EqualityComparer<>).MakeGenericType(fieldType);
    //    next = generator.DefineLabel();
    //    generator.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
    //    generator.Emit(OpCodes.Ldarg_0);
    //    generator.Emit(OpCodes.Ldfld, field);
    //    generator.Emit(OpCodes.Ldloc, other);
    //    generator.Emit(OpCodes.Ldfld, field);
    //    generator.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { fieldType, fieldType }), null);
    //    generator.Emit(OpCodes.Brtrue_S, next);
    //    generator.Emit(OpCodes.Ldc_I4_0);
    //    generator.Emit(OpCodes.Ret);
    //    generator.MarkLabel(next);
    //  }
    //  generator.Emit(OpCodes.Ldc_I4_1);
    //  generator.Emit(OpCodes.Ret);
    //}

    //// This method does not work for Silverlight. It executes but the call to GetHashCode fails with a VerificationException at runtime
    //private static void BuildGetHashCodeMethod(DynamicTypeInfo info, TypeBuilder typBuilder, List<FieldBuilder> fields) {
    //  var mb = typBuilder.DefineMethod("GetHashCode",
    //      MethodAttributes.Public | MethodAttributes.ReuseSlot |
    //      MethodAttributes.Virtual | MethodAttributes.HideBySig,
    //      typeof(int), Type.EmptyTypes);
    //  var generator = mb.GetILGenerator();
    //  generator.Emit(OpCodes.Ldc_I4_0);
    //  var tuples = info.PropertyTypes.Zip(fields, (t, f) => Tuple.Create(t, f));
    //  foreach (var tuple in tuples) {
    //    Type fieldType = tuple.Item1; //  field.FieldType;
    //    var field = tuple.Item2;
    //    Type ct = typeof(EqualityComparer<>).MakeGenericType(fieldType);
    //    generator.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
    //    generator.Emit(OpCodes.Ldarg_0);
    //    generator.Emit(OpCodes.Ldfld, field);
    //    generator.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { fieldType }), null);
    //    generator.Emit(OpCodes.Xor);
    //  }
    //  generator.Emit(OpCodes.Ret);
    //}
    

    private static IEnumerable<FieldBuilder> BuildFields(DynamicTypeInfo info, 
      TypeBuilder typBuilder, GenericTypeParameterBuilder[] parameterBuilders) {
      var propertyCount = info.PropertyNames.Count;
      for (int i = 0; i < propertyCount; i++) {
        yield return typBuilder.DefineField("_" + info.PropertyNames[i], parameterBuilders[i],
          FieldAttributes.Private | FieldAttributes.InitOnly);
      }
    }
    private static void BuildEmptyCtor(DynamicTypeInfo info, TypeBuilder typBuilder) {
      var ctorBuilder = typBuilder.DefineConstructor(
        MethodAttributes.Public |
        MethodAttributes.SpecialName |
        MethodAttributes.RTSpecialName,
        CallingConventions.Standard,
        new Type[0]);

      var generator = ctorBuilder.GetILGenerator();
      generator.Emit(OpCodes.Ldarg_0);
      var baseCtorInfo = typeof(Object).GetConstructor(new Type[0]);
      generator.Emit(OpCodes.Call, baseCtorInfo);
      generator.Emit(OpCodes.Ret);
    }
    private static void BuildProperties(DynamicTypeInfo info, TypeBuilder typBuilder, 
      List<FieldBuilder> fieldBuilders, GenericTypeParameterBuilder[] parameterBuilders) {
      for (int i = 0; i < info.PropertyNames.Count; i++) {
        //var propBuilder = typBuilder.DefineProperty(
        //  info.PropertyNames[i], PropertyAttributes.None, parameterBuilders[i], Type.EmptyTypes);
        var propBuilder = typBuilder.DefineProperty(
          info.PropertyNames[i], PropertyAttributes.HasDefault, parameterBuilders[i], Type.EmptyTypes);

        // Build Get prop
        var getMethBuilder = typBuilder.DefineMethod(
          "get_" + info.PropertyNames[i], MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
          parameterBuilders[i], Type.EmptyTypes);
        var generator = getMethBuilder.GetILGenerator();

        generator.Emit(OpCodes.Ldarg_0); // load 'this'
        generator.Emit(OpCodes.Ldfld, fieldBuilders[i]); // load the field
        generator.Emit(OpCodes.Ret);
        propBuilder.SetGetMethod(getMethBuilder);

        // Build Set prop
        var setMethBuilder = typBuilder.DefineMethod(
          "set_" + info.PropertyNames[i], MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
          typeof(void), new Type[] { fieldBuilders[i].FieldType });
        generator = setMethBuilder.GetILGenerator();

        generator.Emit(OpCodes.Ldarg_0); // load 'this'
        generator.Emit(OpCodes.Ldarg_1); // load value
        generator.Emit(OpCodes.Stfld, fieldBuilders[i]);
        generator.Emit(OpCodes.Ret);
        propBuilder.SetSetMethod(setMethBuilder);
      }
    }
 private static GenericTypeParameterBuilder[] BuildGenericParameters(DynamicTypeInfo info, TypeBuilder typBuilder) {
   // generates the names T0, T1, T2 ...
   String[] parameterNames = Enumerable.Range(0, info.PropertyNames.Count).Select(i => "T" + i.ToString()).ToArray();
   var parameterBuilders = typBuilder.DefineGenericParameters(parameterNames);
   return parameterBuilders;
 }
    private static void BuildCtor(DynamicTypeInfo info, TypeBuilder typBuilder, 
      List<FieldBuilder> fieldBuilders, GenericTypeParameterBuilder[] parameterBuilders) {
      Type[] ctorParams = parameterBuilders;
      var ctorBuilder = typBuilder.DefineConstructor(
        MethodAttributes.Public |
        MethodAttributes.SpecialName |
        MethodAttributes.RTSpecialName,
        CallingConventions.Standard,
        ctorParams);

      ILGenerator ctorIL = ctorBuilder.GetILGenerator();
      ctorIL.Emit(OpCodes.Ldarg_0);
      // var baseCtorInfo = typeof(Object).GetConstructor(new Type[0]);
      var baseCtorInfo = typeof(DynamicTypeBase).GetConstructor(new Type[0]);
      ctorIL.Emit(OpCodes.Call, baseCtorInfo);
      for (byte i = 0; i < info.PropertyNames.Count; i++) {
        ctorIL.Emit(OpCodes.Ldarg_0);
        if (i == 0) {
          ctorIL.Emit(OpCodes.Ldarg_1);
        } else if (i == 1) {
          ctorIL.Emit(OpCodes.Ldarg_2);
        } else if (i == 2) {
          ctorIL.Emit(OpCodes.Ldarg_3);
        } else {
          ctorIL.Emit(OpCodes.Ldarg_S, i + 1);
        }
        ctorIL.Emit(OpCodes.Stfld, fieldBuilders[i]);
      }
      //Get the base constructor

      ctorIL.Emit(OpCodes.Ret);
    }
 private static TypeBuilder BuildType(DynamicTypeInfo info, ModuleBuilder modBuilder) {
   // Build the type
   var typBuilder = modBuilder.DefineType(info.DynamicTypeName,
     TypeAttributes.Public |
     TypeAttributes.Class |
     TypeAttributes.AutoClass |
     TypeAttributes.AnsiClass |
     TypeAttributes.BeforeFieldInit |
     TypeAttributes.AutoLayout,
     // typeof(Object));
     typeof(DynamicTypeBase));
   return typBuilder;
 }
    private static ModuleBuilder BuildModule(DynamicTypeInfo info, AssemblyBuilder asmBuilder) {
      // Build the module
      ModuleBuilder modBuilder;
#if !SILVERLIGHT
      if (info.DynamicTypeShouldSave) {
        modBuilder = asmBuilder.DefineDynamicModule("DynamicAnonTypeModule_" + info.TypeName, asmBuilder.GetName().Name + ".dll");
      } else {
        modBuilder = asmBuilder.DefineDynamicModule("DynamicAnonTypeModule_" + info.TypeName);
      }
#else 
      modBuilder = asmBuilder.DefineDynamicModule("DynamicAnonTypeModule_" + info.TypeName);
#endif
      return modBuilder;
    }
    private static AssemblyBuilder BuildAssembly(DynamicTypeInfo info) {
      AppDomain aDomain = Thread.GetDomain();

      // Build the assembly
      AssemblyName asmName = new AssemblyName();
      asmName.Name = info.DynamicTypeName + DynamicTypeInfo.DynamicAssemblyNameSuffix;
      AssemblyBuilder asmBuilder;
#if !SILVERLIGHT
      if (info.DynamicTypeShouldSave) {
        if (String.IsNullOrEmpty(info.DynamicTypeFileDirectory)) {
          asmBuilder = aDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
        } else {
          asmBuilder = aDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave, info.DynamicTypeFileDirectory);
        }
      } else {
        asmBuilder = aDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
      }
#else 
      asmBuilder = aDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
#endif
      return asmBuilder;
    }
 public TypeShape(DynamicTypeInfo dti) {
   PropertyNames = dti._propertyNames;
   PropertyTypes = dti._propertyTypes;
 }
 private static void AddToMap(DynamicTypeInfo info) {
   if (info._isInMap) return;
   lock (__lock) {
     TypeInfoMap[info.OriginalType] = info;
     TypeInfoNameMap[info.DynamicTypeName] = info;
     if (info.DynamicType == info.OriginalType) {
       TypeShapeMap[new TypeShape(info)] = info;
     }
     info._isInMap = true;
   }
 }