コード例 #1
0
        private static void ReflectionAppend(
            Object lhs,
            Object rhs,
            Type clazz,
            EqualsBuilder builder,
            bool useTransients)
        {
            /*
             * In Java version of this ReflectionAppend, we have to call
             * AccessibleObject.setAccessible() right after class.GetFields() to
             * make non-public fields accessible. In C#, it is easier to do. We simply
             * add BindingFlags.NonPublic, which makes non-public fields accessible
             * (subject to security manager restrictions, of course).
             */
            FieldInfo[] fields = clazz.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
            for (int i = 0; i < fields.Length && builder.isEqual; i++)
            {
                FieldInfo f = fields[i];
                //TODO:atrosin Revise:f.getName().indexOf('$')
                if ((f.Name.IndexOf('$') == -1) &&
                    (useTransients || !isTransient(f)) &&
                    !f.IsStatic)
                {
                    try
                    {
                        builder.Append(f.GetValue(lhs), f.GetValue(rhs));
                    }

                    /*
                     * According to FieldInfo's documentation, getValue() can throw the
                     * following exceptions: TargetException, NotSupportedException,
                     * FieldAccessException and ArgumentException.
                     *
                     * TargetException is thrown if the field is non-static and obj is
                     * a null reference. In our case, the field is non-static (because of
                     * BindingFlags.Instance) but obj should never be null because of
                     * null checks in the calling method (i.e. reflectionEquals()).
                     * I guess we can just throw an unexpected exception.
                     *
                     * NotSupportedException is thrown if the field is marked Literal, but
                     * the field does not have one of the accepted literal types. Literal
                     * means that the field's value is a compile-time (static or early
                     * bound) constant. I think this exception can be just eaten because
                     * constants should always be equal in lhs and rhs and default value
                     * of isEqual is true.
                     *
                     * FieldAccessException is thrown if the caller does not have
                     * permission to access this field. If this code is fully trusted
                     * (not sure how to verify this), access restrictions are ignored.
                     * This means that private fields are accessible. If this code is not
                     * fully trusted, it can still access private fields if this code
                     * has been granted ReflectedPermission with the
                     * ReflectionPermisionFlag.RestrictedMemberAccess flag and if the
                     * grant set of the non-public members is restricted to the caller's
                     * grant set, or subset thereof. Whew, that's a mouthful to say!
                     * I guess it's best just to let FieldAccessException bubble up
                     * to callers so that user can grant permissions, if desired.
                     *
                     * Finally, ArgumentException is thrown if the method is neither
                     * declared nor inherited by the class of obj. This could happen
                     * if lhs is a subclass of rhs (or vice-versa) and the field is
                     * declared in the subclass. In Java, Field.get() would throw
                     * IllegalArgumentException in this case. In Java version of
                     * reflectionAppend(), IllegalArgumentException
                     * bubbles up to reflectionEquals(), where it is dealt with.
                     * It seems logical that use the same technique in the C#
                     * version. That is, we allow ArgumentException to bubble up
                     * to ReflectionEquals() and deal with it there.
                     */
                    catch (TargetException te)
                    {
                        throw new Exception("Unexpected TargetException", te);
                    }
                    catch (NotSupportedException nse)
                    {
                        // eat it!
                    }

                    /* Don't catch FieldAccessException and ArgumentException so that
                     * they can bubble up to caller. Alternatively, we could catch and
                     * rethrow.
                     */
                    //catch (FieldAccessException fae) { throw; }
                    //catch (ArgumentException fae) { throw; }
                }
            }
        }
コード例 #2
0
        public static bool ReflectionEquals(Object lhs, Object rhs, bool testTransients, Type reflectUpToClass)
        {
            if (lhs == rhs)
            {
                return(true);
            }
            if (lhs == null || rhs == null)
            {
                return(false);
            }
            // Find the leaf class since there may be transients in the leaf
            // class or in classes between the leaf and root.
            // If we are not testing transients or a subclass has no ivars,
            // then a subclass can test equals to a superclass.
            Type lhsClass = lhs.GetType();
            Type rhsClass = rhs.GetType();
            Type testClass;

            if (lhsClass.IsInstanceOfType(rhs))
            {
                testClass = lhsClass;
                if (!rhsClass.IsInstanceOfType(lhs))
                {
                    // rhsClass is a subclass of lhsClass
                    testClass = rhsClass;
                }
            }
            else if (rhsClass.IsInstanceOfType(lhs))
            {
                testClass = rhsClass;
                if (!lhsClass.IsInstanceOfType(rhs))
                {
                    // lhsClass is a subclass of rhsClass
                    testClass = lhsClass;
                }
            }
            else
            {
                // The two classes are not related.
                return(false);
            }
            EqualsBuilder equalsBuilder = new EqualsBuilder();

            try
            {
                ReflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
                while (testClass.BaseType != null && testClass != reflectUpToClass)
                {
                    testClass = testClass.BaseType;
                    ReflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
                }
            }
            catch (ArgumentException e)
            {
                // In this case, we tried to test a subclass vs. a superclass and
                // the subclass has ivars or the ivars are transient and
                // we are testing transients.
                // If a subclass has ivars that we are trying to test them, we get an
                // exception and we know that the objects are not equal.
                return(false);
            }
            return(equalsBuilder.IsEquals());
        }