#region Apache Notice /***************************************************************************** * $Header: $ * $Revision: $ * $Date: $ * * iBATIS.NET Data Mapper * Copyright (C) 2004 - Gilles Bayon * * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ********************************************************************************/ #endregion using System; using System.Collections; using System.Reflection; using IBatisNet.Common.Exceptions; namespace IBatisNet.Common.Utilities.Objects { /// /// Description résumée de ObjectProbe. /// public class ObjectProbe { private static ArrayList _simpleTypeMap = new ArrayList(); static ObjectProbe() { _simpleTypeMap.Add(typeof(string)); _simpleTypeMap.Add(typeof(Byte)); _simpleTypeMap.Add(typeof(Int16)); _simpleTypeMap.Add(typeof(char)); _simpleTypeMap.Add(typeof(Int32)); _simpleTypeMap.Add(typeof(Int64)); _simpleTypeMap.Add(typeof(Single)); _simpleTypeMap.Add(typeof(Double)); _simpleTypeMap.Add(typeof(Boolean)); _simpleTypeMap.Add(typeof(DateTime)); _simpleTypeMap.Add(typeof(Decimal)); // _simpleTypeMap.Add(typeof(Hashtable)); // _simpleTypeMap.Add(typeof(SortedList)); // _simpleTypeMap.Add(typeof(ArrayList)); // _simpleTypeMap.Add(typeof(Array)); // simpleTypeMap.Add(LinkedList.class); // simpleTypeMap.Add(HashSet.class); // simpleTypeMap.Add(TreeSet.class); // simpleTypeMap.Add(Vector.class); // simpleTypeMap.Add(Hashtable.class); _simpleTypeMap.Add(typeof(SByte)); _simpleTypeMap.Add(typeof(UInt16)); _simpleTypeMap.Add(typeof(UInt32)); _simpleTypeMap.Add(typeof(UInt64)); _simpleTypeMap.Add(typeof(IEnumerator)); } /// /// Returns an array of the readable properties names exposed by an object /// /// The object /// The properties name public static string[] GetReadablePropertyNames(object obj) { return ReflectionInfo.GetInstance(obj.GetType()).GetReadablePropertyNames(); } /// /// Returns an array of the writeable properties name exposed by a object /// /// The object /// The properties name public static string[] GetWriteablePropertyNames(object obj) { return ReflectionInfo.GetInstance(obj.GetType()).GetWriteablePropertyNames(); } /// /// Returns the type that the set expects to receive as a parameter when /// setting a property value. /// /// The object to check /// The name of the property /// The type of the property public static Type GetPropertyTypeForSetter(object obj, string propertyName) { Type type = obj.GetType(); if (obj is IDictionary) { IDictionary map = (IDictionary) obj; object value = map[propertyName]; if (value == null) { type = typeof(object); } else { type = value.GetType(); } } else { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; type = ReflectionInfo.GetInstance(type).GetSetterType(propertyName); } } else { type = ReflectionInfo.GetInstance(type).GetSetterType(propertyName); } } return type; } /// /// Returns the type that the set expects to receive as a parameter when /// setting a property value. /// /// The type to check /// The name of the property /// The type of the property private static Type GetPropertyTypeForSetter(Type type, string propertyName) { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; type = ReflectionInfo.GetInstance(type).GetSetterType(propertyName); } } else { type = ReflectionInfo.GetInstance(type).GetSetterType(propertyName); } return type; } /// /// Returns the type that the get expects to receive as a parameter when /// setting a property value. /// /// The object to check /// The name of the property /// The type of the property public static Type GetPropertyTypeForGetter(object obj, string propertyName) { Type type = obj.GetType(); if (obj is IDictionary) { IDictionary map = (IDictionary) obj; object value = map[propertyName]; if (value == null) { type = typeof(object); } else { type = value.GetType(); } } else { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; type = ReflectionInfo.GetInstance(type).GetGetterType(propertyName); } } else { type = ReflectionInfo.GetInstance(type).GetGetterType(propertyName); } } return type; } /// /// Returns the type that the get expects to receive as a parameter when /// setting a property value. /// /// The type to check /// The name of the property /// The type of the property public static Type GetPropertyTypeForGetter(Type type, string propertyName) { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; type = ReflectionInfo.GetInstance(type).GetGetterType(propertyName); } } else { type = ReflectionInfo.GetInstance(type).GetGetterType(propertyName); } return type; } /// /// Returns the PropertyInfo of the set property on the specified type. /// /// The type to check /// The name of the property /// The type of the property public static PropertyInfo GetPropertyInfoForSetter(Type type, string propertyName) { PropertyInfo propertyInfo =null; if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); Type parentType = null; while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; parentType = type; type = ReflectionInfo.GetInstance(type).GetSetterType(propertyName); } propertyInfo = ReflectionInfo.GetInstance(parentType).GetSetter(propertyName); } else { propertyInfo = ReflectionInfo.GetInstance(type).GetSetter(propertyName); } return propertyInfo; } private static object GetArrayProperty(object obj, string indexedName) { object value = null; try { int startIndex = indexedName.IndexOf("["); int length = indexedName.IndexOf("]"); string name = indexedName.Substring(0, startIndex); string index = indexedName.Substring( startIndex+1, length-(startIndex+1)); int i = System.Convert.ToInt32(index); if (name.Length > 0) { value = GetProperty(obj, name); } else { value = obj; } if (value is IList) { value = ((IList) value)[i]; } else { throw new ProbeException("The '" + name + "' property of the " + obj.GetType().Name + " class is not a List or Array."); } } catch (ProbeException pe) { throw pe; } catch(Exception e) { throw new ProbeException("Error getting ordinal value from .net object. Cause" + e.Message, e); } return value; } /// /// /// /// /// /// protected static object GetProperty(object obj, string propertyName) { ReflectionInfo reflectionCache = ReflectionInfo.GetInstance(obj.GetType()); try { object value = null; if (propertyName.IndexOf("[") > -1) { value = GetArrayProperty(obj, propertyName); } else { if (obj is IDictionary) { value = ((IDictionary) obj)[propertyName]; } else { PropertyInfo propertyInfo = reflectionCache.GetGetter(propertyName); if (propertyInfo == null) { throw new ProbeException("No Get method for property " + propertyName + " on instance of " + obj.GetType().Name); } try { value = propertyInfo.GetValue(obj, null); } catch (ArgumentException ae) { throw new ProbeException(ae); } catch (TargetException t) { throw new ProbeException(t); } catch (TargetParameterCountException tp) { throw new ProbeException(tp); } catch (MethodAccessException ma) { throw new ProbeException(ma); } } } return value; } catch (ProbeException pe) { throw pe; } catch(Exception e) { throw new ProbeException("Could not Set property '" + propertyName + "' for " + obj.GetType().Name + ". Cause: " + e.Message, e); } } private static void SetArrayProperty(object obj, string indexedName, object value) { try { int startIndex = indexedName.IndexOf("["); int length = indexedName.IndexOf("]"); string name = indexedName.Substring(0, startIndex); string index = indexedName.Substring( startIndex+1, length-(startIndex+1)); int i = System.Convert.ToInt32(index); object list = null; if (name.Length > 0) { list = GetProperty(obj, name); } else { list = obj; } if (list is IList) { ((IList) list)[i] = value; } else { throw new ProbeException("The '" + name + "' property of the " + obj.GetType().Name + " class is not a List or Array."); } } catch (ProbeException pe) { throw pe; } catch (Exception e) { throw new ProbeException("Error getting ordinal value from .net object. Cause" + e.Message, e); } } /// /// /// /// /// /// protected static void SetProperty(object obj, string propertyName, object propertyValue) { ReflectionInfo reflectionCache = ReflectionInfo.GetInstance(obj.GetType()); try { if (propertyName.IndexOf("[") > -1) { SetArrayProperty(obj, propertyName, propertyValue); } else { if (obj is IDictionary) { ((IDictionary) obj)[propertyName] = propertyValue; } else { PropertyInfo propertyInfo = reflectionCache.GetSetter(propertyName); if (propertyInfo == null) { throw new ProbeException("No Set method for property " + propertyName + " on instance of " + obj.GetType().Name); } try { propertyInfo.SetValue(obj, propertyValue, null); } catch (ArgumentException ae) { throw new ProbeException(ae); } catch (TargetException t) { throw new ProbeException(t); } catch (TargetParameterCountException tp) { throw new ProbeException(tp); } catch (MethodAccessException ma) { throw new ProbeException(ma); } } } } catch (ProbeException pe) { throw pe; } catch (Exception e) { throw new ProbeException("Could not Get property '" + propertyName + "' for " + obj.GetType().Name + ". Cause: " + e.Message, e); } } /// /// Return the specified property on an object. /// /// The Object on which to invoke the specified property. /// The name of the property. /// An Object representing the return value of the invoked property. public static object GetPropertyValue(object obj, string propertyName) { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); object value = obj; string token = null; while (enumerator.MoveNext()) { token = (string)enumerator.Current; value = GetProperty(value, token); if (value == null) { break; } } return value; } else { return GetProperty(obj, propertyName); } } /// /// Set the specified property on an object /// /// The Object on which to invoke the specified property. /// The name of the property to set. /// The new value to set. public static void SetPropertyValue(object obj, string propertyName, object propertyValue) { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); enumerator.MoveNext(); string currentPropertyName = (string)enumerator.Current; object child = obj; while (enumerator.MoveNext()) { Type type = GetPropertyTypeForSetter(child, currentPropertyName); object parent = child; child = GetProperty(parent, currentPropertyName); if (child == null) { try { child = Activator.CreateInstance(type); SetPropertyValue(parent, currentPropertyName, child); } catch (Exception e) { throw new ProbeException("Cannot set value of property '" + propertyName + "' because '" + currentPropertyName + "' is null and cannot be instantiated on instance of " + type.Name + ". Cause:" + e.Message, e); } } currentPropertyName = (string)enumerator.Current; } SetProperty(child, currentPropertyName, propertyValue); } else { SetProperty(obj, propertyName, propertyValue); } } /// /// Checks to see if a Object has a writable property/field be a given name /// /// The object to check /// The property to check for /// True if the property exists and is writable public static bool HasWritableProperty(object obj, string propertyName) { bool hasProperty = false; if (obj is IDictionary) { hasProperty = ((IDictionary) obj).Contains(propertyName); } else { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); Type type = obj.GetType(); while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; type = ReflectionInfo.GetInstance(type).GetGetterType(propertyName); hasProperty = ReflectionInfo.GetInstance(type).HasWritableProperty(propertyName); } } else { hasProperty = ReflectionInfo.GetInstance(obj.GetType()).HasWritableProperty(propertyName); } } return hasProperty; } /// /// Checks to see if the Object have a property/field be a given name. /// /// The Object on which to invoke the specified property. /// The name of the property to check for. /// /// True or false if the property exists and is readable. /// public static bool HasReadableProperty(object obj, string propertyName) { bool hasProperty = false; if (obj is IDictionary) { hasProperty = ((IDictionary) obj).Contains(propertyName); } else { if (propertyName.IndexOf('.') > -1) { StringTokenizer parser = new StringTokenizer(propertyName, "."); IEnumerator enumerator = parser.GetEnumerator(); Type type = obj.GetType(); while (enumerator.MoveNext()) { propertyName = (string)enumerator.Current; type = ReflectionInfo.GetInstance(type).GetGetterType(propertyName); hasProperty = ReflectionInfo.GetInstance(type).HasReadableProperty(propertyName); } } else { hasProperty = ReflectionInfo.GetInstance(obj.GetType()).HasReadableProperty(propertyName); } } return hasProperty; } /// /// /// /// /// public static bool IsSimpleType(Type type) { if (_simpleTypeMap.Contains(type)) { return true; } else if (type.IsSubclassOf(typeof(ICollection))) { return true; } else if (type.IsSubclassOf(typeof(IDictionary))) { return true; } else if (type.IsSubclassOf(typeof(IList))) { return true; } else if (type.IsSubclassOf(typeof(IEnumerable))) { return true; } else { return false; } } /// /// Calculates a hash code for all readable properties of a object. /// /// The object to calculate the hash code for. /// The hash code. public static int ObjectHashCode(object obj) { return ObjectHashCode(obj, GetReadablePropertyNames(obj)); } /// /// Calculates a hash code for a subset of the readable properties of a object. /// /// The object to calculate the hash code for. /// A list of the properties to hash. /// The hash code. public static int ObjectHashCode(object obj, string[] properties ) { ArrayList alreadyDigested = new ArrayList(); int hashcode = obj.GetType().FullName.GetHashCode(); for (int i = 0; i < properties.Length; i++) { object value = GetProperty(obj, properties[i]); if (value != null) { if (IsSimpleType(value.GetType())) { hashcode += value.GetHashCode(); hashcode += value.ToString().GetHashCode()*37; } else { // It's a Object // Check to avoid endless loop (circular dependency) if (value != obj) { if (!alreadyDigested.Contains(value)) { alreadyDigested.Add(value); hashcode += ObjectHashCode(value); } } } hashcode *= 29; } } return hashcode; } } }