protected object RawGetObjectProperty(StringTemplate self, object o, string propertyName) { Type c = o.GetType(); object val = null; // Special case: our automatically created Aggregates via // attribute name: "{obj.{prop1,prop2}}" if (c == typeof(StringTemplate.Aggregate)) { val = ((StringTemplate.Aggregate) o).Get(propertyName); return val; } // Special case: if it's a template, pull property from // it's attribute table. // TODO: TJP just asked himself why we can't do inherited attr here? else if (c == typeof(StringTemplate)) { IDictionary attributes = ((StringTemplate) o).Attributes; if (attributes != null) { val = attributes[propertyName]; return val; } } // Special case: if it's an IDictionary then pull using // key not the property method. // // Original intent was to DISALLOW general IDictionary interface // as people could pass in their database masquerading as a IDictionary. // Pragmatism won out ;-) if (typeof(IDictionary).IsAssignableFrom(c)) { IDictionary map = (IDictionary) o; if (propertyName.Equals("keys")) { val = map.Keys; } else if (propertyName.Equals("values")) { val = map.Values; } else if (map.Contains(propertyName)) { val = map[propertyName]; } else { if ( map.Contains(DEFAULT_MAP_VALUE_NAME) ) val = map[DEFAULT_MAP_VALUE_NAME]; } if (val == MAP_KEY_VALUE) { // no property defined; if a map in this group // then there may be a default value val = propertyName; } return val; } // try getXXX and isXXX properties // check cache PropertyLookupParams paramBag; //MemberInfo cachedMember = self.Group.GetCachedClassProperty(c, propertyName); //if ( cachedMember != null ) //{ // try // { // paramBag = new PropertyLookupParams(self, c, o, propertyName, null); // if ( cachedMember is PropertyInfo ) // { // // non-indexed property (since we don't cache indexers) // PropertyInfo pi = (PropertyInfo)cachedMember; // GetPropertyValue(pi, paramBag, ref val); // } // else if ( cachedMember is MethodInfo ) // { // MethodInfo mi = (MethodInfo)cachedMember; // GetMethodValue(mi, paramBag, ref val); // } // else if ( cachedMember is FieldInfo ) // { // // must be a field // FieldInfo fi = (FieldInfo)cachedMember; // GetFieldValue(fi, paramBag, ref val); // } // } // catch (Exception e) // { // self.Error("Can't get property '" + propertyName + // "' from '" + c.FullName + "' instance", e); // } // return val; //} // must look up using reflection // Search for propertyName as: // Property (non-indexed), Method(get_XXX, GetXXX, IsXXX, getXXX, isXXX), Field, this[string] string methodSuffix = Char.ToUpper(propertyName[0]) + propertyName.Substring(1); paramBag = new PropertyLookupParams(self, c, o, propertyName, methodSuffix); totalReflectionLookups++; if (!GetPropertyValueByName(paramBag, ref val)) { bool found = false; foreach (string prefix in new string[] { "get_", "Get", "Is", "get", "is" }) { paramBag.lookupName = prefix + methodSuffix; totalReflectionLookups++; if (found = GetMethodValueByName(paramBag, ref val)) break; } if (!found) { paramBag.lookupName = methodSuffix; totalReflectionLookups++; if (!GetFieldValueByName(paramBag, ref val)) { totalReflectionLookups++; PropertyInfo pi = c.GetProperty("Item", new Type[] { typeof(string) }); if (pi != null) { // TODO: we don't cache indexer PropertyInfo objects (yet?) // it would have complicated getting values from cached property objects try { val = pi.GetValue(o, new object[] { propertyName }); } catch(Exception ex) { self.Error("Can't get property " + propertyName + " via C# string indexer from " + c.FullName + " instance", ex); } } else { self.Error("Class " + c.FullName + " has no such attribute: " + propertyName + " in template context " + self.GetEnclosingInstanceStackString()); } } } } return val; }
private bool GetPropertyValueByName(PropertyLookupParams paramBag, ref object val) { PropertyInfo pi = null; try { pi = paramBag.prototype.GetProperty( paramBag.lookupName, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.IgnoreCase, null, null, Type.EmptyTypes, null ); if (pi != null) { if (pi.CanRead) { // save to avoid [another expensive] lookup later //paramBag.self.Group.CacheClassProperty(paramBag.prototype, paramBag.propertyName, pi); return GetPropertyValue(pi, paramBag, ref val); } else { paramBag.self.Error("Class " + paramBag.prototype.FullName + " property: " + paramBag.lookupName + " is write-only in template context " + paramBag.self.GetEnclosingInstanceStackString()); } } } catch(Exception) { ; } return false; }
private bool GetPropertyValue(PropertyInfo pi, PropertyLookupParams paramBag, ref object @value) { try { @value = pi.GetValue(paramBag.instance, (object[]) null); return true; } catch(Exception ex) { paramBag.self.Error("Can't get property " + paramBag.propertyName + " as CLR property " + pi.Name + " from " + paramBag.prototype.FullName + " instance", ex); } return false; }
private bool GetMethodValueByName(PropertyLookupParams paramBag, ref object val) { MethodInfo mi = null; try { mi = paramBag.prototype.GetMethod( paramBag.lookupName, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.IgnoreCase, null, Type.EmptyTypes, null ); if (mi != null) { // save to avoid [another expensive] lookup later //paramBag.self.Group.CacheClassProperty(paramBag.prototype, paramBag.propertyName, mi); return GetMethodValue(mi, paramBag, ref val); } } catch(Exception) { ; } return false; }
private bool GetMethodValue(MethodInfo mi, PropertyLookupParams paramBag, ref object @value) { try { @value = mi.Invoke(paramBag.instance, (object[]) null); return true; } catch (Exception ex) { paramBag.self.Error("Can't get property " + paramBag.lookupName + " using method get_/Get/Is/get/is as " + mi.Name + " from " + paramBag.prototype.FullName + " instance", ex); } return false; }
private bool GetFieldValue(FieldInfo fi, PropertyLookupParams paramBag, ref object @value) { try { @value = fi.GetValue(paramBag.instance); return true; } catch(Exception ex) { paramBag.self.Error("Can't get property " + fi.Name + " using direct field access from " + paramBag.prototype.FullName + " instance", ex ); } return false; }