示例#1
0
        /// <summary>
        /// Generates a new typed equals method using the given fields.
        /// </summary>
        /// <param name="typeBuilder">The type builder to use.</param>
        /// <param name="fieldsToUse">All fields to use to compute the hash code.</param>
        /// <returns>The created equals function.</returns>
        public static MethodInfo GenerateEquals(
            this TypeBuilder typeBuilder,
            FieldInfo[] fieldsToUse)
        {
            var equals = typeBuilder.DefineMethod(
                EqualsInfo.Name,
                MethodAttributes.Public | MethodAttributes.Virtual |
                MethodAttributes.NewSlot | MethodAttributes.Final,
                typeof(bool),
                new Type[] { typeBuilder });

            var emitter    = new ILEmitter(equals.GetILGenerator());
            var falseLabel = emitter.DeclareLabel();

            foreach (var field in fieldsToUse)
            {
                emitter.Emit(OpCodes.Ldarg_0);
                emitter.Emit(OpCodes.Ldflda, field);

                emitter.Emit(ArgumentOperation.Load, 1);
                emitter.Emit(OpCodes.Ldfld, field);

                emitter.EmitCall(field.FieldType.GetMethod(
                                     EqualsInfo.Name,
                                     new Type[] { field.FieldType }));

                // IMPORTANT: Each field can branch to the false label. However, if we
                // have a large number of fields, depending on the number of IL bytes we
                // emit per field, we may not be able to reach the false label using a
                // 1-byte branch. In that case, we should instead use a 4-byte branch.
                emitter.Emit(
                    fieldsToUse.Length < 7 ? OpCodes.Brfalse_S : OpCodes.Brfalse,
                    falseLabel);
            }

            emitter.EmitConstant(1);
            emitter.Emit(OpCodes.Ret);

            emitter.MarkLabel(falseLabel);
            emitter.EmitConstant(0);
            emitter.Emit(OpCodes.Ret);

            emitter.Finish();
            var equalityInstance = typeof(IEquatable <>).MakeGenericType(typeBuilder);

            typeBuilder.AddInterfaceImplementation(equalityInstance);

            return(equals);
        }
示例#2
0
        /// <summary>
        /// Generates a new hash code function.
        /// </summary>
        /// <param name="typeBuilder">The type builder to use.</param>
        /// <param name="fieldsToUse">All fields to use to compute the hash code.</param>
        /// <returns>The created hash code function.</returns>
        public static MethodInfo GenerateHashCode(
            this TypeBuilder typeBuilder,
            FieldInfo[] fieldsToUse)
        {
            var getHashCode = typeBuilder.DefineMethod(
                GetHashCodeInfo.Name,
                MethodAttributes.Public | MethodAttributes.Virtual,
                typeof(int),
                Array.Empty <Type>());

            var emitter = new ILEmitter(getHashCode.GetILGenerator());
            var result  = emitter.DeclareLocal(typeof(int));

            emitter.EmitConstant(0);
            emitter.Emit(LocalOperation.Store, result);

            foreach (var field in fieldsToUse)
            {
                emitter.Emit(LocalOperation.Load, result);

                emitter.Emit(OpCodes.Ldarg_0);
                emitter.Emit(OpCodes.Ldflda, field);
                emitter.EmitCall(field.FieldType.GetMethod(
                                     GetHashCodeInfo.Name,
                                     BindingFlags.Public | BindingFlags.Instance));

                emitter.Emit(OpCodes.Xor);
                emitter.Emit(LocalOperation.Store, result);
            }

            emitter.Emit(LocalOperation.Load, result);
            emitter.Emit(OpCodes.Ret);

            emitter.Finish();
            typeBuilder.DefineMethodOverride(getHashCode, GetHashCodeInfo);

            return(getHashCode);
        }
示例#3
0
        /// <summary>
        /// Generates a new typed equals method using the given fields.
        /// </summary>
        /// <param name="typeBuilder">The type builder to use.</param>
        /// <param name="fieldsToUse">All fields to use to compute the hash code.</param>
        /// <returns>The created equals function.</returns>
        public static MethodInfo GenerateEquals(
            this TypeBuilder typeBuilder,
            FieldInfo[] fieldsToUse)
        {
            var equals = typeBuilder.DefineMethod(
                EqualsInfo.Name,
                MethodAttributes.Public | MethodAttributes.Virtual |
                MethodAttributes.NewSlot | MethodAttributes.Final,
                typeof(bool),
                new Type[] { typeBuilder });

            var emitter    = new ILEmitter(equals.GetILGenerator());
            var falseLabel = emitter.DeclareLabel();

            foreach (var field in fieldsToUse)
            {
                emitter.Emit(OpCodes.Ldarg_0);
                emitter.Emit(OpCodes.Ldflda, field);

                emitter.Emit(ArgumentOperation.Load, 1);
                emitter.Emit(OpCodes.Ldfld, field);

                emitter.EmitCall(field.FieldType.GetMethod(
                                     EqualsInfo.Name,
                                     new Type[] { field.FieldType }));
                emitter.Emit(OpCodes.Brfalse_S, falseLabel);
            }

            emitter.EmitConstant(1);
            emitter.Emit(OpCodes.Ret);

            emitter.MarkLabel(falseLabel);
            emitter.EmitConstant(0);
            emitter.Emit(OpCodes.Ret);

            emitter.Finish();
            var equalityInstance = typeof(IEquatable <>).MakeGenericType(typeBuilder);

            typeBuilder.AddInterfaceImplementation(equalityInstance);

            return(equals);
        }