| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| using System; |
| using System.Collections; |
| using System.Collections.Generic; |
| using System.Collections.Specialized; |
| using System.Linq; |
| using System.Reflection; |
| using System.Text; |
| using Apache.NMS.AMQP.Transport; |
| |
| namespace Apache.NMS.AMQP.Util |
| { |
| public class PropertyUtil |
| { |
| private const string PROPERTY_TERM_SEPARATOR = "."; |
| public const string PROPERTY_PREFIX = "NMS" + PROPERTY_TERM_SEPARATOR; |
| |
| public static string CreateProperty(string name, string subprefix = "", string prefix = PROPERTY_PREFIX) |
| { |
| string propertyPrefix = prefix + |
| (prefix.Length > 0 && !prefix.EndsWith(PROPERTY_TERM_SEPARATOR) |
| ? |
| PROPERTY_TERM_SEPARATOR |
| : |
| "" |
| ); |
| |
| string subPropertyTerm = subprefix + |
| (subprefix.Length > 0 && !subprefix.EndsWith(PROPERTY_TERM_SEPARATOR) |
| ? |
| PROPERTY_TERM_SEPARATOR |
| : |
| "" |
| ); |
| return propertyPrefix + subPropertyTerm + name; |
| } |
| |
| public static void SetProperties(object obj, StringDictionary properties, string propertyPrefix = PROPERTY_PREFIX) |
| { |
| Dictionary<string, PropertyInfo> props = GetPropertiesForClass(obj); |
| foreach (string rawkey in properties.Keys) |
| { |
| string key = RemovePrefix(propertyPrefix, rawkey); |
| Tracer.DebugFormat("Searching for Property: \"{0}\"", key); |
| if (props.ContainsKey(key)) |
| { |
| Tracer.DebugFormat( |
| "Assigning Property {0} to {1}.{2} with value {3}", |
| key, obj.GetType().Namespace, obj.GetType().Name, properties[rawkey] |
| ); |
| #if NET40 |
| if (props[key].GetSetMethod() != null) |
| #else |
| if(props[key].SetMethod!=null) |
| #endif |
| props[key].SetValue(obj, ConvertType(props[key].PropertyType, properties[rawkey]), null); |
| } |
| |
| } |
| } |
| |
| public static StringDictionary GetProperties(object obj, string propertyPrefix = PROPERTY_PREFIX) |
| { |
| StringDictionary result = new StringDictionary(); |
| Dictionary<string, PropertyInfo> props = GetPropertiesForClass(obj); |
| string propsPrefix = propertyPrefix + |
| ( |
| propertyPrefix.Length > 0 && !propertyPrefix.EndsWith(PROPERTY_TERM_SEPARATOR) |
| ? |
| PROPERTY_TERM_SEPARATOR |
| : |
| "" |
| ); |
| foreach (string key in props.Keys) |
| { |
| object value = props[key].GetValue(obj, null); |
| if (value != null) |
| { |
| result[propertyPrefix + key] = value.ToString(); |
| } |
| } |
| return result; |
| } |
| |
| public static object ConvertType(Type targetType, string value) |
| { |
| if (targetType.IsPrimitive) |
| { |
| return Convert.ChangeType(value, targetType); |
| } |
| else if (targetType.Equals(typeof(string))) |
| { |
| return value; |
| } |
| return null; |
| } |
| |
| private static string RemovePrefix(string prefix, string propertyName) |
| { |
| if (propertyName.StartsWith(prefix, StringComparison.CurrentCultureIgnoreCase) && prefix.Length > 0) |
| { |
| return propertyName.Remove(0, prefix.Length); |
| } |
| else |
| { |
| return propertyName; |
| } |
| } |
| |
| public static Dictionary<string, PropertyInfo> GetPropertiesForClass(object obj) |
| { |
| MemberInfo[] members = obj.GetType().GetMembers(); |
| Dictionary<string, PropertyInfo> properties = new Dictionary<string, PropertyInfo>(); |
| foreach (MemberInfo member in members) |
| { |
| string memberName = member.Name; |
| if (member != null && member is PropertyInfo) |
| { |
| PropertyInfo prop = member as PropertyInfo; |
| properties.Add(memberName.ToLower(), prop); |
| } |
| } |
| return properties; |
| } |
| |
| public static StringDictionary Clone(StringDictionary original) |
| { |
| StringDictionary clone = new StringDictionary(); |
| foreach (string key in original.Keys) |
| { |
| clone.Add(key?.Clone() as string, original[key]?.Clone() as string); |
| } |
| return clone; |
| } |
| |
| /// <summary> |
| /// See <see cref="Merge(StringDictionary, StringDictionary, out StringDictionary, string, string, string)"/> |
| /// </summary> |
| /// <param name="one"></param> |
| /// <param name="other"></param> |
| /// <param name="onePrefix"></param> |
| /// <param name="otherPrefix"></param> |
| /// <param name="mergePrefix"></param> |
| /// <returns></returns> |
| public static StringDictionary Merge( |
| StringDictionary one, |
| StringDictionary other, |
| string onePrefix = PROPERTY_PREFIX, |
| string otherPrefix = PROPERTY_PREFIX, |
| string mergePrefix = PROPERTY_PREFIX |
| ) |
| { |
| StringDictionary d; |
| return Merge(one, other, out d, onePrefix, otherPrefix, mergePrefix); |
| } |
| |
| |
| /// <summary> |
| /// Takes all properties from one StringDictionary and merges them with the other StringDictionary. |
| /// The properties in "one" are prefered over the "other". |
| /// |
| /// </summary> |
| /// <param name="one">StringDictionary containing properties.</param> |
| /// <param name="other">Another StringDictionary containing properties.</param> |
| /// <param name="cross">Holds all the properties from the "other" StringDictionary that are not used because one has the properties.</param> |
| /// <param name="onePrefix">Optional string prefix for the properties in "one".</param> |
| /// <param name="otherPrefix">Optional string prefix for the properties in "other".</param> |
| /// <param name="mergePrefix">Optional string prefix for the properties in result.</param> |
| /// <returns>Merged StringDictionary with properties from both "one" and "other".</returns> |
| public static StringDictionary Merge( |
| StringDictionary one, |
| StringDictionary other, |
| out StringDictionary cross, |
| string onePrefix = PROPERTY_PREFIX, |
| string otherPrefix = PROPERTY_PREFIX, |
| string mergePrefix = PROPERTY_PREFIX |
| ) |
| { |
| if (one == null && other != null) |
| { |
| cross = null; |
| return Clone(other); |
| } |
| else if (one!=null && other == null) |
| { |
| cross = null; |
| return Clone(one); |
| } |
| else if (one == null && other == null) |
| { |
| cross = null; |
| return new StringDictionary(); |
| } |
| StringDictionary result = new StringDictionary(); |
| StringDictionary dups = new StringDictionary(); |
| |
| Array arr = new string[other.Keys.Count]; |
| other.Keys.CopyTo(arr, 0); |
| ArrayList otherKeys = new ArrayList(arr); |
| |
| string mPre = mergePrefix + |
| ( |
| mergePrefix.Length > 0 && !mergePrefix.EndsWith(PROPERTY_TERM_SEPARATOR) |
| ? |
| PROPERTY_TERM_SEPARATOR |
| : |
| "" |
| ); |
| mergePrefix.ToLower(); |
| |
| string onePre = onePrefix + |
| ( |
| onePrefix.Length > 0 && !onePrefix.EndsWith(PROPERTY_TERM_SEPARATOR) |
| ? |
| PROPERTY_TERM_SEPARATOR |
| : |
| "" |
| ); |
| onePre.ToLower(); |
| |
| string otherPre = otherPrefix + |
| ( |
| otherPrefix.Length > 0 && !otherPrefix.EndsWith(PROPERTY_TERM_SEPARATOR) |
| ? |
| PROPERTY_TERM_SEPARATOR |
| : |
| "" |
| ); |
| otherPre.ToLower(); |
| |
| foreach (string rawkey in one.Keys) |
| { |
| string key = RemovePrefix(onePre, rawkey); |
| string otherkey = (otherPre + key).ToLower(); |
| string mergekey = (mPre + key).ToLower(); |
| if (!result.ContainsKey(mergekey)) |
| { |
| result.Add(mergekey, one[rawkey]); |
| } |
| if (other.ContainsKey(otherkey)) |
| { |
| otherKeys.Remove(otherkey); |
| dups.Add(mergekey, other[otherkey]); |
| } |
| } |
| |
| foreach (string rawkey in otherKeys) |
| { |
| string key = RemovePrefix(otherPre, rawkey); |
| result.Add(mPre + key, other[rawkey]); |
| } |
| |
| cross = dups.Count == 0 ? null : dups; |
| return result; |
| } |
| |
| public static string ToString(IList set) |
| { |
| if (set == null) |
| { |
| return "null"; |
| } |
| if (set.Count == 0) |
| { |
| return "[]"; |
| } |
| string result = "["; |
| foreach (object o in set) |
| { |
| result += o.ToString() + ","; |
| } |
| return result.Substring(0, result.Length - 1) + "]"; |
| } |
| |
| private static string ToString(ArrayList set) |
| { |
| if(set == null) |
| { |
| return "null"; |
| } |
| if(set.Count == 0) |
| { |
| return "[]"; |
| } |
| string result = "["; |
| foreach(object o in set) |
| { |
| result += o.ToString() + ","; |
| } |
| return result.Substring(0,result.Length - 1) + "]"; |
| } |
| |
| public static string ToString(StringDictionary properties) |
| { |
| if(properties == null) |
| { |
| return "null"; |
| } |
| if (properties.Count == 0) |
| { |
| return "[]"; |
| } |
| string result = "[\n"; |
| foreach(string s in properties.Keys) |
| { |
| result += string.Format("{0} : {1},\n", s, properties[s]); |
| } |
| return result.Substring(0,result.Length-2) + "\n]"; |
| } |
| |
| public static IDictionary<K,V> Clone<K,V>(IDictionary<K,V> dict) |
| { |
| if (dict == null) return null; |
| Dictionary<K, V> clone = new Dictionary<K, V>(dict.Count); |
| dict.CopyTo(clone.ToArray(), 0); |
| return clone; |
| } |
| |
| public static StringDictionary FilterProperties(StringDictionary properties, string optionPrefix) |
| { |
| if (properties == null) |
| { |
| throw new ArgumentNullException(nameof(properties), "The given properties object was null."); |
| } |
| |
| StringDictionary filtered = new StringDictionary(); |
| foreach (string entry in properties.Keys) |
| { |
| if (entry.StartsWith(optionPrefix)) |
| { |
| string name = entry.Substring(optionPrefix.Length); |
| filtered.Add(name, properties[entry]); |
| } |
| } |
| |
| return filtered; |
| } |
| } |
| |
| #region abstract Property Interceptor classes |
| |
| internal abstract class PropertyInterceptor<T> : StringDictionary where T : class |
| { |
| protected delegate void ApplyProperty(T instance, string key, string value); |
| protected delegate string GetProperty(T instance, string key); |
| protected delegate void ClearProperty(T instance); |
| protected delegate bool CheckProperty(T instance); |
| |
| protected struct Interceptor |
| { |
| public ApplyProperty Setter; |
| public GetProperty Getter; |
| public ClearProperty Reset; |
| public CheckProperty Exists; |
| } |
| |
| |
| private readonly StringDictionary properties; |
| private readonly IDictionary<string, Interceptor> interceptors; |
| private readonly T instance; |
| protected PropertyInterceptor(T instance, StringDictionary properties, IDictionary<string, Interceptor> interceptors) : base() |
| { |
| this.properties = properties; |
| this.instance = instance; |
| |
| // initialize interceptor map |
| this.interceptors = new Dictionary<string, Interceptor>(); |
| foreach (string key in interceptors.Keys) |
| { |
| AddInterceptor(key, interceptors[key]); |
| } |
| |
| } |
| |
| protected T Instance { get { return instance; } } |
| |
| protected StringDictionary Properties { get { return properties; } } |
| |
| protected void AddInterceptor(string key, Interceptor interceptor) |
| { |
| bool updated = false; |
| // add new interceptor |
| if (!interceptors.ContainsKey(key)) |
| { |
| this.interceptors.Add(key, interceptor); |
| } |
| else |
| { |
| // update interceptor |
| // this allows subs classes to override base classes. |
| this.interceptors[key] = interceptor; |
| updated = true; |
| } |
| // Remove intercepted properties from base string dictionary |
| if (properties.ContainsKey(key) || updated) |
| { |
| SetProperty(key, properties[key]); |
| properties.Remove(key); |
| } |
| } |
| |
| protected void AddProperty(string key, string value) |
| { |
| if (interceptors.ContainsKey(key)) |
| { |
| interceptors[key].Setter(instance, key, value); |
| } |
| else |
| { |
| properties.Add(key, value); |
| } |
| } |
| |
| protected void SetProperty(string key, string value) |
| { |
| if (interceptors.ContainsKey(key)) |
| { |
| interceptors[key].Setter(instance, key, value); |
| } |
| else |
| { |
| properties[key] = value; |
| } |
| } |
| |
| protected string GetValue(string key) |
| { |
| string value = null; |
| if (interceptors.ContainsKey(key)) |
| { |
| if (interceptors[key].Exists(instance)) |
| { |
| value = interceptors[key].Getter(instance, key); |
| } |
| } |
| else |
| { |
| value = properties[key]; |
| } |
| return value; |
| } |
| |
| protected int InterceptorCount |
| { |
| get |
| { |
| int count = 0; |
| foreach (string key in interceptors.Keys) |
| { |
| Interceptor i = interceptors[key]; |
| if (i.Exists(instance)) |
| { |
| count++; |
| } |
| } |
| return count; |
| } |
| } |
| |
| #region IDictionary<> Methods |
| |
| public override int Count => this.properties.Count + InterceptorCount; |
| |
| public override void Add(string key, string value) |
| { |
| AddProperty(key, value); |
| } |
| |
| public override string this[string key] |
| { |
| get |
| { |
| return GetValue(key); |
| } |
| set |
| { |
| SetProperty(key, value); |
| } |
| } |
| |
| public override void Clear() |
| { |
| this.properties.Clear(); |
| Interceptor[] set = interceptors.Values.ToArray(); |
| foreach (Interceptor i in set) |
| { |
| i.Reset?.Invoke(Instance); |
| } |
| } |
| |
| public override void Remove(string key) |
| { |
| if (this.properties.ContainsKey(key)) |
| { |
| this.properties.Remove(key); |
| } |
| else if (this.interceptors.ContainsKey(key)) |
| { |
| if (this.interceptors[key].Exists(Instance)) |
| { |
| this.interceptors[key].Reset(Instance); |
| } |
| } |
| } |
| |
| public override bool ContainsKey(string key) |
| { |
| if (this.properties.ContainsKey(key)) |
| { |
| return true; |
| } |
| else if (this.interceptors.ContainsKey(key)) |
| { |
| return this.interceptors[key].Exists(Instance); |
| } |
| return false; |
| } |
| |
| public override ICollection Keys |
| { |
| get |
| { |
| ISet<string> keys = new HashSet<string>(); |
| foreach (string key in interceptors.Keys) |
| { |
| Interceptor i = interceptors[key]; |
| if (i.Exists(instance)) |
| { |
| keys.Add(key); |
| } |
| } |
| foreach (string key in properties.Keys) |
| { |
| keys.Add(key); |
| } |
| |
| return keys.ToList(); |
| } |
| } |
| |
| public override ICollection Values |
| { |
| get |
| { |
| ISet<object> values = new HashSet<object>(); |
| foreach (string key in interceptors.Keys) |
| { |
| Interceptor i = interceptors[key]; |
| if (i.Exists(instance)) |
| { |
| values.Add(i.Getter(instance, key)); |
| } |
| } |
| foreach (object value in properties.Values) |
| { |
| values.Add(value); |
| } |
| |
| return values.ToList(); |
| } |
| } |
| |
| #endregion |
| public override string ToString() |
| { |
| string result = base.ToString(); |
| foreach (string key in Keys) |
| { |
| result += "\n" + key.ToString() + ": " + GetValue(key).ToString(); |
| } |
| return result; |
| } |
| |
| } |
| |
| #region RelfectionPropertyInterceptor |
| |
| internal abstract class ReflectionPropertyInterceptor<T> : PropertyInterceptor<T> where T : class |
| { |
| #region static methods |
| |
| private static bool DefaultExists(T instance) |
| { |
| return true; |
| } |
| |
| private static void SetReflectedValue(PropertyInfo info, object instance, string value) |
| { |
| if (info.GetSetMethod() != null) |
| { |
| object objValue = ParseReflectedValue(info, value); |
| info.SetValue(instance, objValue, null); |
| } |
| } |
| |
| private static object GetReflectedValue(PropertyInfo info, object instance) |
| { |
| object value = null; |
| if (info.GetGetMethod() != null) |
| { |
| value = info.GetValue(instance); |
| } |
| return value; |
| } |
| |
| private static object ParseReflectedValue(PropertyInfo info, string value) |
| { |
| Type targetType = info.PropertyType; |
| return PropertyUtil.ConvertType(targetType, value); |
| } |
| |
| #endregion |
| |
| protected struct ReflectedInteceptor |
| { |
| public PropertyInfo ReflectedProperty; |
| public Interceptor BaseInterceptor; |
| } |
| |
| |
| private Dictionary<string, ReflectedInteceptor> autoInterceptors = null; |
| |
| #region Contructor |
| |
| protected ReflectionPropertyInterceptor(T instance, StringDictionary properties, IDictionary<string, Interceptor> interceptors ) : base(instance, properties, interceptors) |
| { |
| this.autoInterceptors = CreateReflectionInterceptors(instance); |
| if (this.autoInterceptors != null) |
| { |
| foreach (string propertyName in this.autoInterceptors.Keys) |
| { |
| this.AddInterceptor(propertyName, this.autoInterceptors[propertyName].BaseInterceptor); |
| } |
| |
| if (Tracer.IsDebugEnabled) |
| { |
| StringBuilder sb = new StringBuilder(); |
| #if TRACE |
| sb.AppendFormat("Generated {0} reflection properties, Properties = [", this.autoInterceptors.Keys.Count); |
| foreach (string propertyName in this.autoInterceptors.Keys) |
| { |
| sb.AppendFormat("\n\t{0},\n", propertyName); |
| } |
| sb.AppendFormat("]"); |
| #else |
| sb.AppendFormat("Generated {0} reflection properties", this.autoInterceptors.Keys.Count); |
| #endif |
| Tracer.DebugFormat(sb.ToString()); |
| } |
| |
| } |
| } |
| |
| #endregion |
| |
| #region abstract Properties |
| |
| protected abstract string PropertyPrefix { get; } |
| |
| #endregion |
| |
| protected abstract bool CanReflect(PropertyInfo reflectedProperty); |
| |
| #region Private Methods |
| |
| private Interceptor? CreateReflectedInterceptor(PropertyInfo reflectedProperty) |
| { |
| Interceptor? result = null; |
| |
| if (reflectedProperty.GetSetMethod() == null) |
| { |
| |
| } |
| else |
| { |
| |
| |
| ApplyProperty reflectedSetter = (inst, key, value) => |
| { |
| SetReflectedValue(reflectedProperty, inst, value); |
| }; |
| |
| GetProperty reflectedGetter = (inst, key) => |
| { |
| return GetReflectedValue(reflectedProperty, inst)?.ToString(); |
| }; |
| |
| ClearProperty reflectedClear = (inst) => |
| { |
| SetReflectedValue(reflectedProperty, inst, null); |
| }; |
| |
| CheckProperty reflectedExists = DefaultExists; |
| |
| result = new Interceptor() |
| { |
| Getter = reflectedGetter, |
| Setter = reflectedSetter, |
| Reset = reflectedClear, |
| Exists = reflectedExists |
| }; |
| } |
| |
| return result; |
| } |
| |
| private Dictionary<string, ReflectedInteceptor> CreateReflectionInterceptors(T instance) |
| { |
| Dictionary<string, PropertyInfo> objProperties = PropertyUtil.GetPropertiesForClass(instance); |
| |
| Dictionary<string, ReflectedInteceptor> result = new Dictionary<string, ReflectedInteceptor>(); |
| |
| if (Tracer.IsDebugEnabled) |
| { |
| |
| List<string> stringPropertyNames = new List<string>(objProperties.Keys.Count); |
| foreach (string pName in objProperties.Keys) |
| { |
| string propertyName = this.PropertyPrefix + pName; |
| stringPropertyNames.Add(propertyName); |
| } |
| |
| Tracer.DebugFormat("Creating reflection interceptors for Class instance {0}, Generating Properties = {1}", instance.GetType().Name, PropertyUtil.ToString(stringPropertyNames)); |
| } |
| |
| foreach (string key in objProperties.Keys) |
| { |
| string propertyName = this.PropertyPrefix + key; |
| PropertyInfo info = objProperties[key]; |
| if (!CanReflect(info)) continue; |
| //MethodInfo propGetter = info.GetGetMethod(); |
| Interceptor? reflectedInterceptor = CreateReflectedInterceptor(info); |
| if (reflectedInterceptor != null) |
| { |
| Interceptor i = (Interceptor)reflectedInterceptor; |
| ReflectedInteceptor ri = new ReflectedInteceptor() |
| { |
| ReflectedProperty = info, |
| BaseInterceptor = i, |
| }; |
| result.Add(propertyName, ri); |
| } |
| |
| } |
| |
| return result; |
| } |
| |
| #endregion |
| |
| } |
| |
| #endregion // end abstract reflection interception |
| |
| #endregion |
| |
| #region Transport Property Interceptor class |
| |
| internal class SecureTransportPropertyInterceptor : TransportPropertyInterceptor |
| { |
| internal const string SSL_PROTOCOLS_PROPERTY = "transport." + "SSLProtocol"; |
| |
| private static bool ValidateProtocolString(string protocolString, out string cleanProtocols) |
| { |
| const string COMMA = ","; |
| cleanProtocols = protocolString; |
| if (protocolString != null) |
| { |
| string trim = protocolString.Trim(); |
| if(trim.StartsWith(COMMA) || trim.EndsWith(COMMA)) |
| { |
| return false; |
| } |
| cleanProtocols = trim; |
| } |
| return true; |
| } |
| |
| protected static Dictionary<string, Interceptor> secureTransportConextInterceptors = new Dictionary<string, Interceptor>() |
| { |
| { |
| SSL_PROTOCOLS_PROPERTY, |
| new Interceptor() |
| { |
| Getter = (context, key) => |
| { |
| return (context as ISecureTransportContext).SSLProtocol; |
| }, |
| Setter = (context, key, value) => |
| { |
| string cleanValue; |
| if(!ValidateProtocolString(value, out cleanValue)) |
| { |
| throw new InvalidPropertyException(key, "Protocol string can not start or end with ','"); |
| } |
| else |
| { |
| (context as ISecureTransportContext).SSLProtocol = cleanValue; |
| } |
| }, |
| Exists = (context) => |
| { |
| return true; |
| }, |
| Reset = (context) => |
| { |
| (context as ISecureTransportContext).SSLProtocol = null; |
| } |
| } |
| |
| } |
| }; |
| |
| |
| public SecureTransportPropertyInterceptor(ISecureTransportContext context, StringDictionary props ) : base(context, props) |
| { |
| |
| |
| foreach(string key in secureTransportConextInterceptors.Keys) |
| { |
| this.AddInterceptor(key, secureTransportConextInterceptors[key]); |
| } |
| } |
| |
| protected override bool CanReflect(PropertyInfo reflectedProperty) |
| { |
| Type TargetType = reflectedProperty.PropertyType; |
| return TargetType.IsPrimitive || TargetType.Equals(typeof(string)); |
| } |
| |
| } |
| |
| internal class TransportPropertyInterceptor : ReflectionPropertyInterceptor<ITransportContext> |
| { |
| protected static Dictionary<string, Interceptor> transportContextInterceptors = new Dictionary<string, Interceptor>() |
| { |
| |
| }; |
| |
| public TransportPropertyInterceptor(ITransportContext c, StringDictionary transportProperties) : base(c, transportProperties, transportContextInterceptors) |
| { |
| |
| } |
| |
| protected override string PropertyPrefix => "transport."; |
| |
| protected override bool CanReflect(PropertyInfo reflectedProperty) |
| { |
| return true; |
| } |
| |
| } |
| |
| #endregion |
| } |