示例#1
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);

                var fieldHashCode = field.FieldType.GetMethod(
                    GetHashCodeInfo.Name,
                    BindingFlags.Public | BindingFlags.Instance);
                if (!field.FieldType.IsValueType)
                {
                    emitter.Emit(OpCodes.Ldfld, field);
                }
                else if (fieldHashCode.DeclaringType != field.FieldType)
                {
                    // to call GetHashCode inherited from ValueType, struct must be boxed
                    emitter.Emit(OpCodes.Ldfld, field);
                    emitter.Emit(OpCodes.Box, field.FieldType);
                }
                else
                {
                    emitter.Emit(OpCodes.Ldflda, field);
                }

                emitter.EmitCall(fieldHashCode);

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