4 using System.Collections;
5 using System.Collections.Generic;
8 namespace SiliconStudio.Core.Reflection
19 [ThreadStatic]
private static List<object> stackTLS;
21 private readonly List<MemberPathItem> items;
36 items =
new List<MemberPathItem>(capacity);
45 if (items == null)
throw new ArgumentNullException(
"items");
46 this.items =
new List<MemberPathItem>(items.Capacity);
47 this.items.AddRange(items);
56 items.Capacity = pathCount;
72 public T GetCustomAttribute<T>() where T : Attribute
74 if (items == null || items.Count == 0)
79 for(
int i = items.Count - 1; i >= 0; i--)
82 if (descriptor == null)
86 var attributes = descriptor.MemberInfo.GetCustomAttributes(typeof(T),
false);
87 if (attributes.Length > 0)
89 return (T)attributes[0];
104 if (descriptor == null)
throw new ArgumentNullException(
"descriptor");
116 if (descriptor == null)
throw new ArgumentNullException(
"descriptor");
117 AddItem(
new ArrayPathItem(index));
128 if (descriptor == null)
throw new ArgumentNullException(
"descriptor");
129 AddItem(
new CollectionPathItem(descriptor, index));
140 if (descriptor == null)
throw new ArgumentNullException(
"descriptor");
141 AddItem(
new DictionaryPathItem(descriptor, key));
151 items.RemoveAt(items.Count - 1);
157 if (rootObject == null)
throw new ArgumentNullException(
"rootObject");
158 if (rootObject.GetType().IsValueType)
throw new ArgumentException(
"Value type for root objects are not supported",
"rootObject");
161 throw new ArgumentException(
"Value must be null for action != (MemberActionType.SetValue || MemberPathAction.CollectionAdd)");
164 if (items == null || items.Count == 0)
166 throw new InvalidOperationException(
"This instance doesn't contain any path. Use Push() methods to populate paths");
169 var lastItem = items[items.Count - 1];
172 case MemberPathAction.CollectionAdd:
173 if (!(lastItem is CollectionPathItem))
175 throw new ArgumentException(
"Invalid path [{0}] for action [{1}]. Expecting last path to be a collection item".ToFormat(
this, actionType));
178 case MemberPathAction.CollectionRemove:
179 if (!(lastItem is CollectionPathItem) && !(lastItem is ArrayPathItem))
181 throw new ArgumentException(
"Invalid path [{0}] for action [{1}]. Expecting last path to be a collection/array item".ToFormat(
this, actionType));
185 case MemberPathAction.DictionaryRemove:
186 if (!(lastItem is DictionaryPathItem))
188 throw new ArgumentException(
"Invalid path [{0}] for action [{1}]. Expecting last path to be a dictionary item".ToFormat(
this, actionType));
193 var stack = stackTLS;
196 object nextObject = rootObject;
200 stack =
new List<object>();
208 stack.Add(nextObject);
209 for (
int i = 0; i < items.Count - 1; i++)
212 nextObject = item.GetValue(nextObject);
213 stack.Add(nextObject);
218 case MemberPathAction.ValueSet:
219 lastItem.SetValue(stack, stack.Count - 1, nextObject, value);
222 case MemberPathAction.DictionaryRemove:
223 ((DictionaryPathItem)lastItem).Descriptor.Remove(nextObject, ((DictionaryPathItem)lastItem).Key);
226 case MemberPathAction.CollectionAdd:
227 ((CollectionPathItem)lastItem).Descriptor.Add(nextObject, value);
230 case MemberPathAction.CollectionRemove:
231 ((CollectionPathItem)lastItem).Descriptor.RemoveAt(nextObject, ((CollectionPathItem)lastItem).Index);
259 if (rootObject == null)
throw new ArgumentNullException(
"rootObject");
263 object nextObject = rootObject;
264 for (
int i = 0; i < items.Count; i++)
267 nextObject = item.GetValue(nextObject);
289 if (rootObject == null)
throw new ArgumentNullException(
"rootObject");
290 if (items.Count == 0)
throw new InvalidOperationException(
"No items pushed via Push methods");
293 overrideType = OverrideType.Base;
296 object nextObject = rootObject;
298 var lastItem = items[items.Count - 1];
299 var memberDescriptor = lastItem.MemberDescriptor;
301 for (
int i = 0; i < items.Count - 1; i++)
304 nextObject = item.GetValue(nextObject);
307 overrideType = nextObject.GetOverride(memberDescriptor);
308 value = lastItem.GetValue(nextObject);
334 var text =
new StringBuilder();
336 foreach (var memberPathItem
in items)
338 text.Append(memberPathItem.GetName(isFirst));
341 return text.ToString();
344 private void AddItem(MemberPathItem item)
346 var previousItem = items.Count > 0 ? items[items.Count - 1] : null;
348 item.Parent = previousItem;
351 private abstract class MemberPathItem
353 public MemberPathItem Parent {
get; set; }
357 public abstract object GetValue(
object thisObj);
359 public abstract void SetValue(List<object> stack,
int objectIndex,
object thisObject,
object value);
361 public abstract string GetName(
bool isFirst);
364 private sealed
class PropertyPathItem : MemberPathItem
366 private readonly PropertyDescriptor Descriptor;
368 private readonly
bool isValueType;
370 public PropertyPathItem(PropertyDescriptor descriptor)
372 this.Descriptor = descriptor;
373 isValueType = descriptor.DeclaringType.IsValueType;
384 public override object GetValue(
object thisObj)
386 return Descriptor.Get(thisObj);
389 public override void SetValue(List<object> stack,
int objectIndex,
object thisObject,
object value)
391 Descriptor.Set(thisObject, value);
393 if (isValueType && Parent != null)
395 Parent.SetValue(stack, objectIndex - 1, stack[objectIndex-1], thisObject);
399 public override string GetName(
bool isFirst)
401 return isFirst ? Descriptor.Name :
"." + Descriptor.Name;
405 private sealed
class FieldPathItem : MemberPathItem
407 private readonly FieldDescriptor Descriptor;
408 private readonly
bool isValueType;
410 public FieldPathItem(FieldDescriptor descriptor)
412 this.Descriptor = descriptor;
413 isValueType = descriptor.DeclaringType.IsValueType;
424 public override object GetValue(
object thisObj)
426 return Descriptor.Get(thisObj);
429 public override void SetValue(List<object> stack,
int objectIndex,
object thisObject,
object value)
431 Descriptor.Set(thisObject, value);
433 if (isValueType && Parent != null)
435 Parent.SetValue(stack, objectIndex - 1, stack[objectIndex - 1], thisObject);
439 public override string GetName(
bool isFirst)
441 return "." + Descriptor.Name;
445 private abstract class SpecialMemberPathItemBase : MemberPathItem
457 private sealed
class ArrayPathItem : SpecialMemberPathItemBase
459 private readonly
int index;
461 public ArrayPathItem(
int index)
466 public override object GetValue(
object thisObj)
468 return ((Array)thisObj).GetValue(index);
471 public override void SetValue(List<object> stack,
int objectIndex,
object thisObject,
object value)
473 ((
Array)thisObject).SetValue(value, index);
476 public override string GetName(
bool isFirst)
478 return "[" + index +
"]";
482 private sealed
class CollectionPathItem : SpecialMemberPathItemBase
484 public readonly CollectionDescriptor Descriptor;
486 public readonly
int Index;
488 public CollectionPathItem(CollectionDescriptor descriptor,
int index)
490 this.Descriptor = descriptor;
494 public override object GetValue(
object thisObj)
496 return Descriptor.GetValue(thisObj, Index);
499 public override void SetValue(List<object> stack,
int objectIndex,
object thisObject,
object value)
501 Descriptor.SetValue(thisObject, Index, value);
504 public override string GetName(
bool isFirst)
506 return "[" + Index +
"]";
510 private sealed
class DictionaryPathItem : SpecialMemberPathItemBase
512 public readonly DictionaryDescriptor Descriptor;
514 public readonly
object Key;
516 public DictionaryPathItem(DictionaryDescriptor descriptor,
object key)
518 this.Descriptor = descriptor;
522 public override object GetValue(
object thisObj)
524 return Descriptor.GetValue(thisObj, Key);
527 public override void SetValue(List<object> stack,
int objectIndex,
object thisObject,
object value)
529 Descriptor.SetValue(thisObject, Key, value);
532 public override string GetName(
bool isFirst)
534 return "[" + Key +
"]";
Provides a descriptor for a System.Collections.ICollection.
A IMemberDescriptor for a PropertyInfo
bool TryGetValue(object rootObject, out object value)
Gets the value from the specified root object following this instance path.
void EnsureCapacity(int pathCount)
Ensures the capacity of the paths definition when using Push(SiliconStudio.Core.Reflection.IMemberDescriptor) methods.
Describe a member of an object.
void Pop()
Pops the last item from the current path.
Provides a descriptor for a System.Collections.IDictionary.
MemberPath()
Initializes a new instance of the MemberPath class.
void Push(CollectionDescriptor descriptor, int index)
Pushes an collection access on the path.
void Push(ArrayDescriptor descriptor, int index)
Pushes an array access on the path.
A IMemberDescriptor for a FieldInfo
Allows to get/set a property/field value on a deeply nested object instance (supporting members...
void Clear()
Clears the current path.
void Push(DictionaryDescriptor descriptor, object key)
Pushes an dictionary access on the path.
MemberPath Clone()
Clones this instance, cloning the current path.
OverrideType
A Type of override used on a member value.
bool TryGetValue(object rootObject, out object value, out OverrideType overrideType)
Gets the value from the specified root object following this instance path.
Base class for IMemberDescriptor for a MemberInfo
A descriptor for an array.
void Push(IMemberDescriptor descriptor)
Pushes a member access on the path.
override string ToString()
Returns a System.String that represents this instance.
bool Apply(object rootObject, MemberPathAction actionType, object value)
MemberPathAction
A type of action used by MemberPath.Apply
MemberPath(int capacity)
Initializes a new instance of the MemberPath class.