// 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); }
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)); }