private TupleType TupleTypeFromNative(System.Type type) { var tupleType = new TupleType(); // Get attributes foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) tupleType.Attributes.Add(Name.FromNative(field.Name), TypeFromNative(field.FieldType)); // Get references foreach (TupleReferenceAttribute r in type.GetCustomAttributes(typeof(TupleReferenceAttribute))) tupleType.References.Add ( Name.FromNative(r.Name), new TupleReference { SourceAttributeNames = (from san in r.SourceAttributeNames select Name.FromNative(san)).ToArray(), Target = Name.FromNative(r.Target), TargetAttributeNames = (from tan in r.TargetAttributeNames select Name.FromNative(tan)).ToArray() } ); // Get keys foreach (TupleKeyAttribute k in type.GetCustomAttributes(typeof(TupleKeyAttribute))) tupleType.Keys.Add ( new TupleKey { AttributeNames = (from n in k.AttributeNames select Name.FromNative(n)).ToArray() } ); return tupleType; }
private static MethodBuilder EmitTupleGetHashCode(TupleType tupleType, TypeBuilder typeBuilder, Dictionary<Name, FieldInfo> fieldsByID) { var getHashCodeMethod = typeBuilder.DefineMethod("GetHashCode", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot, CallingConventions.HasThis, typeof(Int32), new System.Type[] { }); var il = getHashCodeMethod.GetILGenerator(); // result = 83 il.Emit(OpCodes.Ldc_I4, 83); foreach (var keyItem in tupleType.GetKeyAttributes()) { var field = fieldsByID[keyItem]; // result ^= this.<field>.GetHashCode(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldflda, field); il.Emit(OpCodes.Constrained, field.FieldType); il.EmitCall(OpCodes.Callvirt, ReflectionUtility.ObjectGetHashCode, null); il.Emit(OpCodes.Xor); } il.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(getHashCodeMethod, ReflectionUtility.ObjectGetHashCode); return getHashCodeMethod; }
public System.Type NativeFromTupleType(TupleType tupleType) { var typeBuilder = _module.DefineType("Tuple" + tupleType.GetHashCode(), TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Serializable, typeof(ValueType)); var fieldsByID = new Dictionary<Name, FieldInfo>(); // Add attributes foreach (var attribute in tupleType.Attributes) { var field = typeBuilder.DefineField(attribute.Key.ToString(), attribute.Value.GetNative(this), FieldAttributes.Public); fieldsByID.Add(attribute.Key, field); } // Add references foreach (var reference in tupleType.References) { var cab = new CustomAttributeBuilder ( typeof(TupleReferenceAttribute).GetConstructor(new System.Type[] { typeof(string), typeof(string[]), typeof(string), typeof(string[]) }), new object[] { reference.Key.ToString(), (from san in reference.Value.SourceAttributeNames select san.ToString()).ToArray(), reference.Value.Target.ToString(), (from tan in reference.Value.TargetAttributeNames select tan.ToString()).ToArray(), } ); typeBuilder.SetCustomAttribute(cab); } // Add keys foreach (var key in tupleType.Keys) { var cab = new CustomAttributeBuilder ( typeof(TupleKeyAttribute).GetConstructor(new System.Type[] { typeof(string[]) }), new object[] { (from an in key.AttributeNames select an.ToString()).ToArray() } ); typeBuilder.SetCustomAttribute(cab); } // Add tuple attribute var attributeBuilder = new CustomAttributeBuilder ( typeof(TupleAttribute).GetConstructor(new System.Type[] { }), new object[] { } ); typeBuilder.SetCustomAttribute(attributeBuilder); // Add comparison and hash methods based on key(s) EmitTupleGetHashCode(tupleType, typeBuilder, fieldsByID); var equalityMethod = EmitTupleEquality(tupleType, typeBuilder, fieldsByID); EmitTupleInequality(typeBuilder, equalityMethod); EmitTupleEquals(typeBuilder, equalityMethod); // Create the type return typeBuilder.CreateType(); }
private static MethodBuilder EmitTupleEquality(TupleType tupleType, TypeBuilder typeBuilder, Dictionary<Name, FieldInfo> fieldsByID) { var equalityMethod = typeBuilder.DefineMethod("op_Equality", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, CallingConventions.Standard, typeof(bool), new System.Type[] { typeBuilder, typeBuilder }); var il = equalityMethod.GetILGenerator(); var end = il.DefineLabel(); foreach (var keyItem in tupleType.GetKeyAttributes()) { var field = fieldsByID[keyItem]; il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, field); var fieldEqualityMethod = field.FieldType.GetMethod("op_Equality", new System.Type[] { field.FieldType, field.FieldType }); if (fieldEqualityMethod != null) il.EmitCall(OpCodes.Call, fieldEqualityMethod, null); else il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, end); il.Emit(OpCodes.Pop); } il.Emit(OpCodes.Ldc_I4_1); // True il.MarkLabel(end); il.Emit(OpCodes.Ret); return equalityMethod; }
public System.Type FindOrCreateNativeFromTupleType(TupleType tupleType) { System.Type nativeType; if (!_tupleToNative.TryGetValue(tupleType, out nativeType)) { nativeType = NativeFromTupleType(tupleType); _tupleToNative.Add(tupleType, nativeType); } return nativeType; }