// vsadov: need to take ctor parameters too as they do not
        // necessarily match properties order as returned by GetProperties
        /// <summary>
        /// The get or create anonymous type for.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="properties">
        /// The properties.
        /// </param>
        /// <param name="ctrParams">
        /// The ctr params.
        /// </param>
        /// <returns>
        /// </returns>
        public Type GetOrCreateAnonymousTypeFor(string name, NameTypePair[] properties, NameTypePair[] ctrParams)
        {
            var id = new AnonTypeId(name, properties.Concat(ctrParams));

            if (this.anonymousTypes.ContainsKey(id))
            {
                return(this.anonymousTypes[id]);
            }

            // vsadov: VB anon type. not necessary, just looks better
            var anonPrefix      = name.StartsWith("<>") ? "<>f__AnonymousType" : "VB$AnonymousType_";
            var anonTypeBuilder = this.moduleBuilder.DefineType(
                anonPrefix + this.anonymousTypeIndex++, TypeAttributes.Public | TypeAttributes.Class);

            var fieldBuilders    = new FieldBuilder[properties.Length];
            var propertyBuilders = new PropertyBuilder[properties.Length];

            for (int i = 0; i < properties.Length; i++)
            {
                fieldBuilders[i] = anonTypeBuilder.DefineField(
                    "_generatedfield_" + properties[i].Name, properties[i].Type, FieldAttributes.Private);
                propertyBuilders[i] = anonTypeBuilder.DefineProperty(
                    properties[i].Name, PropertyAttributes.None, properties[i].Type, new Type[0]);
                var propertyGetterBuilder = anonTypeBuilder.DefineMethod(
                    "get_" + properties[i].Name, MethodAttributes.Public, properties[i].Type, new Type[0]);
                var getterIlGenerator = propertyGetterBuilder.GetILGenerator();
                getterIlGenerator.Emit(OpCodes.Ldarg_0);
                getterIlGenerator.Emit(OpCodes.Ldfld, fieldBuilders[i]);
                getterIlGenerator.Emit(OpCodes.Ret);
                propertyBuilders[i].SetGetMethod(propertyGetterBuilder);
            }

            var constructorBuilder =
                anonTypeBuilder.DefineConstructor(
                    MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Public,
                    CallingConventions.Standard,
                    ctrParams.Select(prop => prop.Type).ToArray());
            var constructorIlGenerator = constructorBuilder.GetILGenerator();

            for (var i = 0; i < ctrParams.Length; i++)
            {
                constructorIlGenerator.Emit(OpCodes.Ldarg_0);
                constructorIlGenerator.Emit(OpCodes.Ldarg, i + 1);
                constructorIlGenerator.Emit(OpCodes.Stfld, fieldBuilders[i]);
                constructorBuilder.DefineParameter(i + 1, ParameterAttributes.None, ctrParams[i].Name);
            }

            constructorIlGenerator.Emit(OpCodes.Ret);

            // TODO - Define ToString() and GetHashCode implementations for our generated Anonymous Types
            // MethodBuilder toStringBuilder = anonTypeBuilder.DefineMethod();
            // MethodBuilder getHashCodeBuilder = anonTypeBuilder.DefineMethod();
            var anonType = anonTypeBuilder.CreateType();

            this.anonymousTypes.Add(id, anonType);
            return(anonType);
        }
Exemple #2
0
            public override bool Equals(object obj)
            {
                if (!(obj is AnonTypeId))
                {
                    return(false);
                }
                AnonTypeId other = obj as AnonTypeId;

                return(Name.Equals(other.Name) &&
                       Properties.SequenceEqual(other.Properties));
            }