18 BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance;
28 GetMemberInfo(propertyExpression).Name;
37 Expression body = expression.Body;
39 while (body is UnaryExpression unaryExpression)
40 body = unaryExpression.Operand;
41 if (body is MemberExpression memberExpression)
42 return memberExpression.Member;
43 throw new ArgumentException(
"No MemberExpression found in " + expression.GetType().NiceTypeName());
49 while (toCheck !=
null && toCheck != typeof(
object))
51 Type cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
54 toCheck = toCheck.BaseType;
68 MemberInfo propertyInfo = GetMemberInfo(expression);
69 return propertyInfo.IsAttributeDefinedFast(attributeType);
72 #region Cached Attribute Retrieval
74 private static readonly ConcurrentDictionary<Tuple<string, Type, Type>,
object>
75 CachedPropertyAttributes =
new ConcurrentDictionary<Tuple<string, Type, Type>,
object>();
92 return member.GetCustomAttributeFast(attributeType) !=
null;
110 Tuple<string, Type, Type> cacheKey =
111 Tuple.Create(member.Name, member.DeclaringType, attributeType);
112 object result = CachedPropertyAttributes.GetOrAdd(cacheKey, key =>
114 try {
return Attribute.GetCustomAttribute(member, attributeType,
true); }
115 catch (Exception ex) {
return ex; }
117 if (result is Exception exceptionResult)
118 throw exceptionResult;
121 #endregion Cached Attribute Retrieval
123 #region GetUserFacingProperties
127 private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>
128 CachedUserFacingProperties =
new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
148 bool excludeServerGenerated =
false,
149 bool excludeNotWritable =
false,
150 bool excludeNotSerialized =
false)
153 throw new ArgumentNullException(nameof(type),
"Could not determine the declaring type.");
155 return CachedUserFacingProperties.GetOrAdd(
156 Tuple.Create(type, excludeServerGenerated, excludeNotWritable, excludeNotSerialized),
157 CachedUserFacingProperties_OnAdd);
161 private static PropertyInfo[] CachedUserFacingProperties_OnAdd(
162 Tuple<Type, bool, bool, bool> key)
164 Type type = key.Item1;
165 bool excludeServerGenerated = key.Item2;
166 bool excludeNotWritable = key.Item3;
167 bool excludeNotSerialized = key.Item4;
170 .Where(pi => pi.CanRead &&
172 !pi.IsAttributeDefinedFast<ObsoleteAttribute>());
173 if(excludeServerGenerated)
174 filtered = filtered.Where(pi => !pi.IsAttributeDefinedFast<
ServerGenerated>());
175 if (excludeNotWritable)
176 filtered = filtered.Where(pi => pi.CanWrite);
177 if (excludeNotSerialized)
178 filtered = filtered.Where(pi => !pi.IsAttributeDefinedFast<IgnoreDataMemberAttribute>());
184 Dictionary<string, PropertyInfo> propertiesByName =
new Dictionary<string, PropertyInfo>();
185 foreach (PropertyInfo property
in filtered)
187 if (!propertiesByName.TryGetValue(property.Name, out PropertyInfo conflicting) ||
188 conflicting.DeclaringType.IsAssignableFrom(property.DeclaringType))
189 propertiesByName[
property.Name] = property;
192 return propertiesByName.Values.ToArray();
194 #endregion GetUserFacingProperties
196 #region GetPublicProperties
198 private static readonly ConcurrentDictionary<Type, PropertyInfo[]> CachedPublicProperties =
199 new ConcurrentDictionary<Type, PropertyInfo[]>();
209 throw new ArgumentNullException(nameof(type),
"Could not determine the declaring type.");
210 return CachedPublicProperties.GetOrAdd(type, GetPublicProperties_Fast_OnAdd);
214 private static PropertyInfo[] GetPublicProperties_Fast_OnAdd(Type type)
217 if (!type.IsInterface)
220 List<PropertyInfo> propertyInfos =
new List<PropertyInfo>();
221 List<Type> considered =
new List<Type>();
222 Queue<Type> queue =
new Queue<Type>();
223 considered.Add(type);
225 while (queue.Count > 0)
227 Type subType = queue.Dequeue();
228 foreach (Type subInterface
in subType.GetInterfaces()
229 .Where(subInterface => !considered.Contains(subInterface)))
231 considered.Add(subInterface);
232 queue.Enqueue(subInterface);
234 IEnumerable<PropertyInfo> newPropertyInfos =
236 .Where(x => !propertyInfos.Contains(x));
237 propertyInfos.InsertRange(0, newPropertyInfos);
239 return propertyInfos.ToArray();
241 #endregion GetPublicProperties
243 #region GetPublicFields
245 private static readonly ConcurrentDictionary<Type, FieldInfo[]> CachedPublicFields =
246 new ConcurrentDictionary<Type, FieldInfo[]>();
256 throw new ArgumentNullException(nameof(type),
"Could not determine the declaring type.");
258 return type.IsInterface ?
new FieldInfo[] { } :
261 #endregion GetPublicFields
268 T obj = Activator.CreateInstance<T>();
270 foreach (PropertyInfo propertyInfo
in typeof(T).GetPublicProperties_Fast()
271 .Where(p => p.CanWrite))
272 propertyInfo.SetValue(obj, propertyInfo.GetValue(toCopy,
null),
null);
274 foreach (FieldInfo fieldInfo
in typeof(T).GetPublicFields_Fast())
275 fieldInfo.SetValue(obj, fieldInfo.GetValue(toCopy));