/** * */ /// <summary> /// Appends the fields and values defined by the given object of the given Class. /// </summary> /// <param name="builder">the builder to Append to</param> /// <param name="clazz">the class to Append details of</param> /// <param name="obj">the object to Append details of</param> /// <param name="useTransients">whether to use transient fields</param> private static void reflectionAppend(object obj, Type clazz, HashCodeBuilder builder, bool useTransients) { //TODO: atrosin what does it mean? f.Name.IndexOf('$') //TODO: atrosin //AccessibleObject.setAccessible(fields, true); FieldInfo[] fields = clazz.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField); //AccessibleObject.setAccessible(fields, true); for (int i = 0; i < fields.Length; i++) { FieldInfo f = fields[i]; if ((f.Name.IndexOf('$') == -1) && (useTransients || !isTransient(f)) && !f.IsStatic) { try { builder.Append(f.GetValue(obj)); } //TODO: atrosin revise for more specific exc. catch (Exception e) { //this can't happen. Would get a Security exception instead //throw a runtime exception in case the impossible happens. throw new Exception("Unexpected IllegalAccessException"); } } } }
/// <summary> /// This method uses reflection to build a valid hash code. /// /// It uses AccessibleObject.setAccessible to gain access to private /// fields. This means that it will throw a security exception if run under /// a security manager, if the permissions are not set up correctly. It is also /// not as efficient as testing explicitly. /// /// If the TestTransients parameter is set to true, transient /// members will be tested, otherwise they are ignored, as they are likely /// derived fields, and not part of the value of the Object. /// /// Static fields will not be included. Superclass fields will be included /// up to and including the specified superclass. A null superclass is treated /// as java.lang.Object. /// /// Two randomly chosen, non-zero, odd numbers must be passed in. Ideally /// these should be different for each class, however this is not vital. /// Prime numbers are preferred, especially for the multiplier. /// Throws IllegalArgumentException if the Object is null /// Throws IllegalArgumentException if the number is zero or even since 2.0 /// </summary> /// <param name="initialNonZeroOddNumber">a non-zero, odd number used as the initial value</param> /// <param name="multiplierNonZeroOddNumber">a non-zero, odd number used as the multiplier</param> /// <param name="obj">the Object to create a hashCode for</param> /// <param name="reflectUpToClass">whether to include transient fields</param> /// <param name="testTransients">the superclass to reflect up to (inclusive),may be null</param> /// <returns>hash code</returns> public static int ReflectionHashCode( int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object obj, bool testTransients, Type reflectUpToClass) { if (obj == null) { throw new ArgumentException("The object to build a hash code for must not be null"); } HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber); Type clazz = obj.GetType(); reflectionAppend(obj, clazz, builder, testTransients); while (clazz.BaseType != null && clazz != reflectUpToClass) { clazz = clazz.BaseType; reflectionAppend(obj, clazz, builder, testTransients); } return(builder.ToHashCode()); }
private static void ReflectionAppend(object obj, IReflect clazz, HashCodeBuilder builder, bool useTransients) { var fields = clazz.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField); foreach (var f in fields) { if ((f.Name.IndexOf('$') != -1) || (!useTransients && IsTransient(f)) || f.IsStatic) { continue; } try { builder.Append(f.GetValue(obj)); } catch (Exception) { throw new Exception("Unexpected IllegalAccessException"); } } }