Ejemplo n.º 1
0
            private MethodDefinition OverrideGetHashCode(
                TypeDefinition caseClassTypeDefinition,
                IEnumerable <CaseClassProperty> properties,
                FieldVarietyDetector fieldVarietyDetector)
            {
                var method = new MethodDefinition(
                    nameof(GetHashCode),
                    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
                    _typeSystem.Int32Reference);

                var getHashCodeMethod = _moduleDefinition.ImportReference(
                    _typeSystem.ObjectDefinition.Methods.Single(x => x.Name == nameof(GetHashCode)));
                var getHashCodeOfValueTypeMethod = _moduleDefinition.ImportReference(
                    _findType(typeof(ValueType).FullName).Methods.Single(m => m.Name == nameof(GetHashCode)));

                var codeEmitter = method.Body.GetILProcessor();

                codeEmitter.Emit(OpCodes.Ldc_I4, 857327845);

                foreach (var property in properties)
                {
                    codeEmitter.Emit(OpCodes.Ldc_I4, -1521134295);
                    codeEmitter.Emit(OpCodes.Mul);

                    var doAddition = Instruction.Create(OpCodes.Add);
                    if (fieldVarietyDetector.Detect(property.BackingFieldReference.FieldType).IsReferenceType ?? true)
                    {
                        var callGetHashCode = Instruction.Create(OpCodes.Callvirt, getHashCodeMethod);
                        property.BoxFieldValue(codeEmitter);
                        codeEmitter.Emit(OpCodes.Dup);
                        codeEmitter.Emit(OpCodes.Brtrue_S, callGetHashCode);
                        codeEmitter.Emit(OpCodes.Pop);
                        codeEmitter.Emit(OpCodes.Ldc_I4_0);
                        codeEmitter.Emit(OpCodes.Br_S, doAddition);
                        codeEmitter.Append(callGetHashCode);
                    }
                    else
                    {
                        codeEmitter.Emit(OpCodes.Ldarg_0);
                        codeEmitter.Emit(OpCodes.Ldfld, property.BackingFieldReference);
                        codeEmitter.Emit(OpCodes.Call, getHashCodeOfValueTypeMethod);
                    }

                    codeEmitter.Append(doAddition);
                }

                codeEmitter.Emit(OpCodes.Ret);

                return(method);
            }
Ejemplo n.º 2
0
            public void EmitEqualityCheck(ILProcessor compareCodeEmitter, FieldVarietyDetector fieldVarietyDetector)
            {
                switch (fieldVarietyDetector.Detect(BackingFieldReference.FieldType))
                {
                case ReferenceTypeImplementingIEquatable referenceTypeImplementingIEquatable:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.EquatableReferencesAreEqual),
                        referenceTypeImplementingIEquatable.FieldType);
                    break;

                case TypedCollection typedCollection:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.TypedCollectionsAreEqual),
                        typedCollection.ElementType);
                    break;

                case UntypedColection _:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.UntypedCollectionsAreEqual));
                    break;

                case PlainReferenceType plainReferenceType:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.ReferenceInstancesAreEqual),
                        plainReferenceType.FieldType);
                    break;

                case ValueTypeImplementingIEquatable valueTypeImplementingIEquatable:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.EquatableValuesAreEqual),
                        valueTypeImplementingIEquatable.FieldType);
                    break;

                case PlainValueType plainValueType:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.ValueInstancesAreEqual),
                        plainValueType.FieldType);
                    break;

                case NullableTypeImplementingIEquatable nullableTypeImplementingIEquatable:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.EquatableNullablesAreEqual),
                        nullableTypeImplementingIEquatable.UnderlyingType);
                    break;

                case PlainNullableType plainNullableType:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.NullablesAreEqual),
                        plainNullableType.UnderlyingType);
                    break;

                case GenericTypeImplementingIEquatable genericTypeImplementingIEquatable:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.EquatableGenericsAreEqual),
                        genericTypeImplementingIEquatable.GenericParameter);
                    break;

                case PlainGenericType plainGenericType:
                    EmitFieldEqualityTestingCode(
                        compareCodeEmitter,
                        nameof(DeepEqualityComparer.GenericsAreEqual),
                        plainGenericType.GenericParameter);
                    break;

                case FieldVariety fieldVariety:
                    throw new InvalidOperationException($"Program logic exception: no code to handle {fieldVariety.GetType()} field variety.");
                }
            }