- /// <summary>
- /// A sequential access parser (api) for parsing a types graph
- /// </summary>
- /// <remarks>
- /// Throws an <see cref="InvalidOperationException"/> if a cyclic
- /// dependency is found.
- /// </remarks>
- public class SapTypeParser
- {
- private readonly List<Type> _isMapped = new List<Type>(3);
- private readonly Type _type;
- private char _pathSeperator;
- public enum Continuation
- {
- Continue,
- Stop,
- Skip
- };
- public delegate Continuation ParseTypeEventHandler(Type type, ref string path);
- public delegate Continuation ParsePropertyEventHandler(PropertyInfo property, ref string path);
- public event ParseTypeEventHandler OnType;
- public event ParsePropertyEventHandler ScalarProperty;
- public event ParsePropertyEventHandler ClassProperty;
- public event ParsePropertyEventHandler EnumerableProperty;
- public event ParsePropertyEventHandler OnProperty;
- public SapTypeParser(Type type)
- {
- _type = type;
- }
- public void Parse(Func<PropertyInfo, bool> predicate = null, char pathSeperator = '.')
- {
- _pathSeperator = pathSeperator;
- predicate = predicate ?? ((p) => true);
- Parse(_type, string.Empty, predicate);
- }
- protected virtual Continuation Parse(Type type, string path, Func<PropertyInfo, bool> predicate)
- {
- if (_isMapped.Contains(type))
- throw new InvalidOperationException(
- string.Format(
- "A cyclic dependency has been identified for type {0} ({1})! We cannot parse cyclic dependant graphs.",
- type.Name, path));
- if (OnType != null)
- {
- var continuation = OnType(type, ref path);
- if (!Continue(ref continuation)) return continuation;
- }
- var properties = type.GetProperties().Where(predicate);
- return ParseProperties(properties, path, predicate);
- }
- private Continuation ParseProperties(IEnumerable<PropertyInfo> properties, string path,
- Func<PropertyInfo, bool> predicate)
- {
- Continuation continuation = Continuation.Continue;
- foreach (var property in properties)
- {
- if (OnProperty != null)
- {
- continuation = OnProperty(property, ref path);
- }
- if (continuation == Continuation.Continue)
- {
- if (IsEnumerable(property))
- {
- if (EnumerableProperty != null)
- {
- continuation = EnumerableProperty(property, ref path);
- // we currently don't support enumerates
- }
- }
- else if (IsCustomClass(property))
- {
- if (ClassProperty != null)
- {
- continuation = ClassProperty(property, ref path);
- if (continuation == Continuation.Continue)
- {
- continuation = Parse(property.PropertyType, Append(path, property.Name), predicate);
- }
- }
- }
- else
- {
- if (ScalarProperty != null)
- {
- continuation = ScalarProperty(property, ref path);
- }
- }
- }
- if (continuation == Continuation.Stop) return continuation;
- }
- return Continuation.Continue;
- }
- private bool Continue(ref Continuation continuation)
- {
- switch (continuation)
- {
- case Continuation.Skip:
- continuation = Continuation.Continue;
- return false;
- case Continuation.Stop:
- return false;
- case Continuation.Continue:
- return true;
- default:
- throw new NotImplementedException("Continuation value is not supported! Internal error.");
- }
- }
- private string Append(string path, string name)
- {
- if (string.IsNullOrEmpty(path)) return name;
- path.TrimEnd(_pathSeperator);
- return string.Format("{0}{1}{2}", path, _pathSeperator, name);
- }
- private static bool IsCustomClass(PropertyInfo property)
- {
- return (Type.GetTypeCode(property.PropertyType) == TypeCode.Object);
- }
- private static bool IsEnumerable(PropertyInfo property)
- {
- var type = property.PropertyType;
- return typeof (IEnumerable).IsAssignableFrom(type) && Type.GetTypeCode(type) != TypeCode.String;
- }
- }
- //该片段来自于http://www.codesnippet.cn/detail/080120131406.html
来源: http://www.codesnippet.cn/detail/080120131406.html