diff --git a/.gitignore b/.gitignore index 78b49ee..c7dbce2 100644 --- a/.gitignore +++ b/.gitignore @@ -229,3 +229,4 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +.dtbcache.v2 \ No newline at end of file diff --git a/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryFormatter.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryFormatter.cs new file mode 100644 index 0000000..d20f770 --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryFormatter.cs @@ -0,0 +1,46 @@ +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; +using GraphClimber.Examples; +using GraphClimber.Examples.Binary; + +namespace GraphClimber.ConsoleApp.Examples.Binary +{ + public class BinaryFormatter + { + private readonly IGraphClimber _binaryReader; + private readonly IGraphClimber _binaryWriter; + + public BinaryFormatter() + { + IStateMemberProvider provider = new BinaryStateMemberProvider(new PropertyStateMemberProvider()); + _binaryReader = DefaultGraphClimber.Create(provider); + _binaryWriter = DefaultGraphClimber.Create(provider); + } + + public object Deserialize(IReader reader) + { + return Deserialize(reader); + } + + public T Deserialize(IReader reader) + { + BinaryReaderProcessor processor = new BinaryReaderProcessor(reader); + StrongBox box = new StrongBox(); + _binaryReader.Climb(box, processor); + return box.Value; + } + + public void Serialize(IWriter writer, object graph) + { + Serialize(writer, graph); + } + + public void Serialize(IWriter writer, T graph) + { + BinaryWriterProcessor processor = new BinaryWriterProcessor(writer); + StrongBox box = new StrongBox(){Value = graph}; + _binaryWriter.Climb(box, processor); + } + } +} \ No newline at end of file diff --git a/src/GraphClimber/Examples/Binary/BinaryReaderProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryReaderProcessor.cs similarity index 97% rename from src/GraphClimber/Examples/Binary/BinaryReaderProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/BinaryReaderProcessor.cs index be93dfb..9b4138f 100644 --- a/src/GraphClimber/Examples/Binary/BinaryReaderProcessor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryReaderProcessor.cs @@ -10,7 +10,8 @@ internal class BinaryReaderWriterExtensions public static bool IsPredefinedType(Type type) { return type.IsPrimitive || type.IsEnum || - type == typeof(string) || type == typeof(DateTime); + type == typeof(string) || type == typeof(DateTime) || + type.IsArray; } } @@ -42,11 +43,12 @@ public void ProcessReferenceType(IWriteOnlyExactValueDescriptor descriptor if (TryReadReferenceType(descriptor, out type)) { // Do not create instance when predefined type, Just route to it. - if (BinaryReaderWriterExtensions.IsPredefinedType(type)) + if (BinaryReaderWriterExtensions.IsPredefinedType(type) || + type.IsArray) { descriptor.Route( new BinaryStateMember - (new MyCustomStateMember((IReflectionStateMember) descriptor.StateMember, + (new MyCustomStateMember(descriptor.StateMember, type), true, true), @@ -210,7 +212,7 @@ public void ProcessForWriteOnly(IWriteOnlyExactValueDescriptor descripto if (TryReadReferenceType(descriptor, out type)) { string value = _reader.ReadString(); - _objects.Add(value); + //_objects.Add(value); descriptor.Set(value); } } @@ -283,7 +285,7 @@ private int[] ReadIntArray() public void ProcessEnumForWriteOnly<[IsEnum] TEnum, TUnderlying> (IEnumReadWriteExactValueDescriptor descriptor) where TUnderlying : IConvertible - where TEnum : IConvertible + where TEnum : Enum, IConvertible { IStateMember underlying = descriptor.UnderlyingValueStateMember; diff --git a/src/GraphClimber/Examples/Binary/BinaryStateMemberProvider.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryStateMemberProvider.cs similarity index 66% rename from src/GraphClimber/Examples/Binary/BinaryStateMemberProvider.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/BinaryStateMemberProvider.cs index e06db47..1a4815f 100644 --- a/src/GraphClimber/Examples/Binary/BinaryStateMemberProvider.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryStateMemberProvider.cs @@ -18,17 +18,16 @@ public BinaryStateMemberProvider(IStateMemberProvider underlying) public IEnumerable Provide(Type type) { return _underlying.Provide(type) - .Select(x => new BinaryStateMember((IReflectionStateMember)x)); + .Select(x => new BinaryStateMember(x)); } - public IStateMember ProvideArrayMember(Type arrayType, int[] indices) + public IStateMember ProvideArrayMember(Type arrayType, int arrayLength) { - return new BinaryStateMember((IReflectionStateMember) - _underlying.ProvideArrayMember(arrayType, indices)); + return new BinaryStateMember(_underlying.ProvideArrayMember(arrayType, arrayLength)); } } - public class BinaryStateMember : IReflectionStateMember + public class BinaryStateMember : IStateMember { private readonly IStateMember _stateMember; private readonly bool _knownType; @@ -97,25 +96,17 @@ public Type RuntimeType get { return _stateMember.MemberType; } } - public Expression GetGetExpression(Expression obj) + public Expression GetGetExpression(Expression obj, Expression indices) { - return _stateMember.GetGetExpression(obj); + return _stateMember.GetGetExpression(obj, indices); } - public Expression GetSetExpression(Expression obj, Expression value) + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) { - return _stateMember.GetSetExpression(obj, value); + return _stateMember.GetSetExpression(obj, indices, value); } - public bool IsArrayElement - { - get { return _stateMember.IsArrayElement; } - } - - public int[] ElementIndex - { - get { return _stateMember.ElementIndex; } - } + public IEnumerable Aliases => _stateMember.Aliases; public bool KnownType { @@ -132,42 +123,6 @@ public bool HeaderHandled get { return _headerHandled; } } - public MemberInfo UnderlyingMemberInfo - { - get - { - var reflectionStateMember = _stateMember as IReflectionStateMember; - if (reflectionStateMember != null) - { - return reflectionStateMember.UnderlyingMemberInfo; - } - - throw new NotImplementedException(); - } - } - - public object GetValue(object owner) - { - var reflectionStateMember = _stateMember as IReflectionStateMember; - if (reflectionStateMember != null) - { - return reflectionStateMember.GetValue(owner); - } - - throw new NotImplementedException(); - } - - public void SetValue(object owner, object value) - { - var reflectionStateMember = _stateMember as IReflectionStateMember; - if (reflectionStateMember != null) - { - reflectionStateMember.SetValue(owner, value); - } - - throw new NotImplementedException(); - } - protected bool Equals(BinaryStateMember other) { return Equals(_stateMember, other._stateMember) && _knownType.Equals(other._knownType); diff --git a/src/GraphClimber/Examples/Binary/BinaryWriterProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryWriterProcessor.cs similarity index 97% rename from src/GraphClimber/Examples/Binary/BinaryWriterProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/BinaryWriterProcessor.cs index 3f5b1da..1d37bf4 100644 --- a/src/GraphClimber/Examples/Binary/BinaryWriterProcessor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Binary/BinaryWriterProcessor.cs @@ -16,12 +16,12 @@ public static class ReadWriteHeader class ReferenceEqualityComparer : IEqualityComparer { - public bool Equals(object x, object y) + bool IEqualityComparer.Equals(object x, object y) { return ReferenceEquals(x, y); } - public int GetHashCode(object obj) + int IEqualityComparer.GetHashCode(object obj) { if (obj == null) { @@ -47,6 +47,8 @@ public BinaryWriterProcessor(IWriter writer) [ProcessorMethod(Precedence = 102)] public void Process(IReadOnlyValueDescriptor descriptor) { + var children = descriptor.Children; + T objectToSerialize = descriptor.Get(); var runtimeType = objectToSerialize.GetType(); @@ -142,7 +144,7 @@ public void ProcessArray<[IsArray]TArray>(IReadOnlyExactValueDescriptor public void ProcessEnumForReadOnly<[IsEnum]TEnum, TUnderlying> (IReadOnlyEnumExactValueDescriptor descriptor) where TUnderlying : IConvertible - where TEnum : IConvertible + where TEnum : Enum { WriteAssemblyQualifiedNameIfNeeded((BinaryStateMember)descriptor.StateMember, typeof (TEnum)); diff --git a/src/GraphClimber/Examples/Binary/IWriter.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/IWriter.cs similarity index 100% rename from src/GraphClimber/Examples/Binary/IWriter.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/IWriter.cs diff --git a/src/GraphClimber/Examples/Binary/IsArrayAttribute.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/IsArrayAttribute.cs similarity index 100% rename from src/GraphClimber/Examples/Binary/IsArrayAttribute.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/IsArrayAttribute.cs diff --git a/src/GraphClimber/Examples/Binary/PositionRestore.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/PositionRestore.cs similarity index 100% rename from src/GraphClimber/Examples/Binary/PositionRestore.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/PositionRestore.cs diff --git a/src/GraphClimber/Examples/Binary/SuperBinaryWriter.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/SuperBinaryReader.cs similarity index 74% rename from src/GraphClimber/Examples/Binary/SuperBinaryWriter.cs rename to src/GraphClimber.ConsoleApp/Examples/Binary/SuperBinaryReader.cs index 07c731e..a788f9f 100644 --- a/src/GraphClimber/Examples/Binary/SuperBinaryWriter.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Binary/SuperBinaryReader.cs @@ -1,52 +1,10 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; -using System.Threading.Tasks; namespace GraphClimber.Examples { - - class SuperBinaryWriter : BinaryWriter - { - private readonly IDictionary _writtenStrings = new Dictionary(); - - protected SuperBinaryWriter() - { - } - - public SuperBinaryWriter(Stream output) : base(output) - { - } - - public SuperBinaryWriter(Stream output, Encoding encoding) : base(output, encoding) - { - } - - public SuperBinaryWriter(Stream output, Encoding encoding, bool leaveOpen) : base(output, encoding, leaveOpen) - { - } - - public override void Write(string value) - { - int id; - if (_writtenStrings.TryGetValue(value, out id)) - { - base.Write((byte)1); - base.Write(id); - } - else - { - _writtenStrings[value] = _writtenStrings.Count; - base.Write((byte)0); - base.Write(value); - } - } - } - - - class SuperBinaryReader : BinaryReader + internal class SuperBinaryReader : BinaryReader { private readonly IList _readStrings = new List(); @@ -64,7 +22,7 @@ public SuperBinaryReader(Stream input, Encoding encoding, bool leaveOpen) : base public override string ReadString() { - var isRead = base.ReadByte(); + byte isRead = base.ReadByte(); if (isRead == 1) { @@ -202,4 +160,4 @@ public override int GetHashCode() return base.GetHashCode(); } } -} +} \ No newline at end of file diff --git a/src/GraphClimber.ConsoleApp/Examples/Binary/SuperBinaryWriter.cs b/src/GraphClimber.ConsoleApp/Examples/Binary/SuperBinaryWriter.cs new file mode 100644 index 0000000..2dd4dd8 --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Examples/Binary/SuperBinaryWriter.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace GraphClimber.Examples +{ + internal class SuperBinaryWriter : BinaryWriter + { + private readonly IDictionary _writtenStrings = new Dictionary(); + + protected SuperBinaryWriter() + { + } + + public SuperBinaryWriter(Stream output) : base(output) + { + } + + public SuperBinaryWriter(Stream output, Encoding encoding) : base(output, encoding) + { + } + + public SuperBinaryWriter(Stream output, Encoding encoding, bool leaveOpen) : base(output, encoding, leaveOpen) + { + } + + public override void Write(string value) + { + int id; + if (_writtenStrings.TryGetValue(value, out id)) + { + base.Write((byte)1); + base.Write(id); + } + else + { + _writtenStrings[value] = _writtenStrings.Count; + base.Write((byte)0); + base.Write(value); + } + } + } +} diff --git a/src/GraphClimber/Examples/Extractor/Extractor.cs b/src/GraphClimber.ConsoleApp/Examples/Extractor/Extractor.cs similarity index 55% rename from src/GraphClimber/Examples/Extractor/Extractor.cs rename to src/GraphClimber.ConsoleApp/Examples/Extractor/Extractor.cs index a911824..350aca4 100644 --- a/src/GraphClimber/Examples/Extractor/Extractor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Extractor/Extractor.cs @@ -4,19 +4,20 @@ namespace GraphClimber.Examples { public class Extractor { - private readonly SlowGraphClimber> _climber; + private readonly IGraphClimber> _climber; public Extractor() { _climber = - new SlowGraphClimber>(new ReflectionPropertyStateMemberProvider()); + DefaultGraphClimber> + .Create(new PropertyStateMemberProvider()); } public void Extract(object value, Action callback) { ExtractorProcessor processor = new ExtractorProcessor(callback); - _climber.Route(value, processor, false); + _climber.Climb(new Box() {Value = value}, processor); } } } \ No newline at end of file diff --git a/src/GraphClimber/Examples/Extractor/ExtractorProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Extractor/ExtractorProcessor.cs similarity index 100% rename from src/GraphClimber/Examples/Extractor/ExtractorProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Extractor/ExtractorProcessor.cs diff --git a/src/GraphClimber/Examples/MyCustomStateMember.cs b/src/GraphClimber.ConsoleApp/Examples/MyCustomStateMember.cs similarity index 62% rename from src/GraphClimber/Examples/MyCustomStateMember.cs rename to src/GraphClimber.ConsoleApp/Examples/MyCustomStateMember.cs index ff0ef66..1ca4bd1 100644 --- a/src/GraphClimber/Examples/MyCustomStateMember.cs +++ b/src/GraphClimber.ConsoleApp/Examples/MyCustomStateMember.cs @@ -1,30 +1,33 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; namespace GraphClimber.Examples { - public class MyCustomStateMember : IReflectionStateMember + public class MyCustomStateMember : IStateMember { - private readonly IReflectionStateMember _underlying; + private readonly IStateMember _underlying; private readonly Type _memberType; - public MyCustomStateMember(IReflectionStateMember underlying, Type memberType) + public MyCustomStateMember(IStateMember underlying, Type memberType) { _underlying = underlying; _memberType = memberType; } - public int[] ElementIndex + public Expression GetGetExpression(Expression obj, Expression indices) { - get { return _underlying.ElementIndex; } + return _underlying.GetGetExpression(obj, indices); } - public bool IsArrayElement + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) { - get { return _underlying.IsArrayElement; } + return _underlying.GetSetExpression(obj, indices, value); } + public IEnumerable Aliases => _underlying.Aliases; + public string Name { get { return _underlying.Name; } @@ -53,31 +56,6 @@ public bool CanWrite get { return _underlying.CanWrite; } } - public Expression GetGetExpression(Expression obj) - { - return _underlying.GetGetExpression(obj); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - return _underlying.GetSetExpression(obj, value); - } - - public MemberInfo UnderlyingMemberInfo - { - get { return _underlying.UnderlyingMemberInfo; } - } - - public object GetValue(object owner) - { - return _underlying.GetValue(owner); - } - - public void SetValue(object owner, object value) - { - _underlying.SetValue(owner, value); - } - protected bool Equals(MyCustomStateMember other) { return Equals(_underlying, other._underlying) && Equals(_memberType, other._memberType); diff --git a/src/GraphClimber/Examples/OldGames.cs b/src/GraphClimber.ConsoleApp/Examples/OldGames.cs similarity index 100% rename from src/GraphClimber/Examples/OldGames.cs rename to src/GraphClimber.ConsoleApp/Examples/OldGames.cs diff --git a/src/GraphClimber/Examples/Store/IStore.cs b/src/GraphClimber.ConsoleApp/Examples/Store/IStore.cs similarity index 100% rename from src/GraphClimber/Examples/Store/IStore.cs rename to src/GraphClimber.ConsoleApp/Examples/Store/IStore.cs diff --git a/src/GraphClimber/Examples/Store/StoreReaderProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Store/StoreReaderProcessor.cs similarity index 83% rename from src/GraphClimber/Examples/Store/StoreReaderProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Store/StoreReaderProcessor.cs index 25e6714..62072ec 100644 --- a/src/GraphClimber/Examples/Store/StoreReaderProcessor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Store/StoreReaderProcessor.cs @@ -19,20 +19,21 @@ public StoreReaderProcessor(IStore store) public void Process(IWriteOnlyValueDescriptor descriptor) { string type; + + IStore temp = _store; + + _store = _store.GetInner(descriptor.StateMember.Name); + if (_store.TryGet("Type", out type)) { - var value = (T)Activator.CreateInstance(Type.GetType(type)); descriptor.Set(value); - var temp = _store; - _store = _store.GetInner(descriptor.StateMember.Name); - descriptor.Climb(); - - _store = temp; } + + _store = temp; } [ProcessorMethod(Precedence = 99)] @@ -43,17 +44,16 @@ public void ProcessPrimitives<[Primitive]T>(IWriteOnlyExactValueDescriptor de { descriptor.Set(value); } - } [ProcessorMethod] public void Process(IWriteOnlyValueDescriptor descriptor) { - string type; + IStore innerStore = _store.GetInner(descriptor.StateMember.Name); - if (_store.TryGet("Type", out type)) + if (innerStore.TryGet("Type", out string type)) { - descriptor.Route(new MyCustomStateMember((IReflectionStateMember)descriptor.StateMember, Type.GetType(type)), descriptor.Owner, true); + descriptor.Route(new MyCustomStateMember(descriptor.StateMember, Type.GetType(type)), descriptor.Owner, true); } } diff --git a/src/GraphClimber.ConsoleApp/Examples/Store/StoreSerializer.cs b/src/GraphClimber.ConsoleApp/Examples/Store/StoreSerializer.cs new file mode 100644 index 0000000..aa2fe8c --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Examples/Store/StoreSerializer.cs @@ -0,0 +1,33 @@ +namespace GraphClimber.Examples +{ + public class StoreSerializer + { + private readonly IGraphClimber _storeWriterClimber; + private readonly IGraphClimber _storeReaderClimber; + + public StoreSerializer() + { + IStateMemberProvider stateMemberProvider = new PropertyStateMemberProvider(); + _storeWriterClimber = DefaultGraphClimber.Create(stateMemberProvider); + _storeReaderClimber = DefaultGraphClimber.Create(stateMemberProvider); + } + + public void Write(object value, IStore store) + { + Box box = new Box() {Value = value}; + _storeWriterClimber.Climb(box, new StoreWriterProcessor(store)); + } + + public object Read(IStore store) + { + return Read(store); + } + + public T Read(IStore store) + { + Box box = new Box(); + _storeReaderClimber.Climb(box, new StoreReaderProcessor(store)); + return box.Value; + } + } +} \ No newline at end of file diff --git a/src/GraphClimber/Examples/Store/StoreWriterProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Store/StoreWriterProcessor.cs similarity index 98% rename from src/GraphClimber/Examples/Store/StoreWriterProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Store/StoreWriterProcessor.cs index 9479727..f54e809 100644 --- a/src/GraphClimber/Examples/Store/StoreWriterProcessor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Store/StoreWriterProcessor.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using System.Collections.Generic; using GraphClimber.ValueDescriptor; @@ -19,11 +18,10 @@ public StoreWriterProcessor(IStore store) public void Process(IReadOnlyValueDescriptor descriptor) { var value = descriptor.Get(); - _store.Set("Type", value.GetType().AssemblyQualifiedName); - var temp = _store; _store = _store.GetInner(descriptor.StateMember.Name); + _store.Set("Type", value.GetType().AssemblyQualifiedName); descriptor.Climb(); diff --git a/src/GraphClimber/Examples/Store/TrivialStore.cs b/src/GraphClimber.ConsoleApp/Examples/Store/TrivialStore.cs similarity index 100% rename from src/GraphClimber/Examples/Store/TrivialStore.cs rename to src/GraphClimber.ConsoleApp/Examples/Store/TrivialStore.cs diff --git a/src/GraphClimber.ConsoleApp/Examples/Xml/Box.cs b/src/GraphClimber.ConsoleApp/Examples/Xml/Box.cs new file mode 100644 index 0000000..3a8b98a --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Examples/Xml/Box.cs @@ -0,0 +1,11 @@ +namespace GraphClimber.Examples +{ + internal class Box : Box + { + public T Value { get; set; } + } + + internal class Box + { + } +} \ No newline at end of file diff --git a/src/GraphClimber/Examples/Xml/XmlReaderProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Xml/XElementReaderProcessor.cs similarity index 63% rename from src/GraphClimber/Examples/Xml/XmlReaderProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Xml/XElementReaderProcessor.cs index a39191c..9baaf7c 100644 --- a/src/GraphClimber/Examples/Xml/XmlReaderProcessor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Xml/XElementReaderProcessor.cs @@ -3,11 +3,11 @@ namespace GraphClimber.Examples { - internal class XmlReaderProcessor + internal class XElementReaderProcessor { private XElement _reader; - public XmlReaderProcessor(XElement reader) + public XElementReaderProcessor(XElement reader) { _reader = reader; } @@ -30,9 +30,16 @@ public void ProcessString(IWriteOnlyExactValueDescriptor descriptor) XElement element = _reader.Element(descriptor.StateMember.Name); - string result = element.Value; + if ((element != null) && !element.IsEmpty) + { + string result = element.Value; - descriptor.Set(result); + descriptor.Set(result); + } + else + { + descriptor.Set(null); + } } [ProcessorMethod(Precedence = 102)] @@ -40,16 +47,23 @@ public void ProcessGeneric(IWriteOnlyValueDescriptor descriptor) { XElement temp = _reader; - _reader = _reader.Element(descriptor.StateMember.Name); - - CreateObject(descriptor); + if (!(descriptor.Owner is Box)) + { + _reader = _reader.Element(descriptor.StateMember.Name); + } - descriptor.Climb(); + if (_reader != null) + { + if (CreateObject(descriptor)) + { + descriptor.Climb(); + } + } _reader = temp; } - private void CreateObject(IWriteOnlyValueDescriptor descriptor) + private bool CreateObject(IWriteOnlyValueDescriptor descriptor) { XAttribute attribute = _reader.Attribute("Type"); @@ -63,13 +77,22 @@ private void CreateObject(IWriteOnlyValueDescriptor descriptor) (T) Activator.CreateInstance(instanceType); descriptor.Set(field); + + return true; } + + return false; } [ProcessorMethod] public void ProcessObject(IWriteOnlyExactValueDescriptor descriptor) { - XElement element = _reader.Element(descriptor.StateMember.Name); + XElement element = _reader; + + if (!(descriptor.Owner is Box)) + { + element = _reader.Element(descriptor.StateMember.Name); + } XAttribute attribute = element.Attribute("Type"); @@ -81,11 +104,9 @@ public void ProcessObject(IWriteOnlyExactValueDescriptor descriptor) // TODO: this will be the route method.. descriptor.Route - (new MyCustomStateMember((IReflectionStateMember) descriptor.StateMember, + (new MyCustomStateMember(descriptor.StateMember, instanceType), descriptor.Owner, true); } } - - } } \ No newline at end of file diff --git a/src/GraphClimber.ConsoleApp/Examples/Xml/XmlSerializer.cs b/src/GraphClimber.ConsoleApp/Examples/Xml/XmlSerializer.cs new file mode 100644 index 0000000..e06f849 --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Examples/Xml/XmlSerializer.cs @@ -0,0 +1,53 @@ +using System.Xml; +using System.Xml.Linq; + +namespace GraphClimber.Examples +{ + public class XmlSerializer + { + private readonly IGraphClimber _writerClimber; + private readonly IGraphClimber _readerClimber; + private readonly IGraphClimber _newReaderClimber; + + public XmlSerializer() + { + IStateMemberProvider memberProvider = new CachingStateMemberProvider(new PropertyStateMemberProvider()); + + _newReaderClimber = DefaultGraphClimber.Create(memberProvider); + _readerClimber = DefaultGraphClimber.Create(memberProvider); + _writerClimber = DefaultGraphClimber.Create(memberProvider); + } + + public void Serialize(T value, XmlWriter writer) + { + XmlWriterProcessor processor = new XmlWriterProcessor(writer); + _writerClimber.Climb(new Box {Value = value}, processor); + } + + public object Deserialize(XElement element) + { + return Deserialize(element); + } + + public T Deserialize(XElement element) + { + XElementReaderProcessor processor = new XElementReaderProcessor(element); + Box box = new Box(); + _readerClimber.Climb(box, processor); + return box.Value; + } + + public object Deserialize(XmlReader reader) + { + return Deserialize(reader); + } + + public T Deserialize(XmlReader reader) + { + XmlTextReaderProcessor processor = new XmlTextReaderProcessor(reader); + Box box = new Box(); + _newReaderClimber.Climb(box, processor); + return box.Value; + } + } +} \ No newline at end of file diff --git a/src/GraphClimber.ConsoleApp/Examples/Xml/XmlTextReaderProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Xml/XmlTextReaderProcessor.cs new file mode 100644 index 0000000..1a71ea3 --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Examples/Xml/XmlTextReaderProcessor.cs @@ -0,0 +1,101 @@ +using System; +using System.Xml; + +namespace GraphClimber.Examples +{ + public class XmlTextReaderProcessor + { + private readonly XmlReader _reader; + + public XmlTextReaderProcessor(XmlReader reader) + { + _reader = reader; + } + + [ProcessorMethod(Precedence = 104)] + public void ProcessGeneric(IWriteOnlyValueDescriptor descriptor) + { + XmlReader reader = _reader; + + object owner = CreateObject(descriptor); + + reader.Read(); + + while (reader.NodeType != XmlNodeType.EndElement) + { + if (reader.NodeType == XmlNodeType.Element) + { + IStateMember member; + if (descriptor.Children.TryGetValue(reader.Name, out member)) + { + descriptor.Route(member, owner, false); + } + } + } + } + + [ProcessorMethod] + public void ProcessObject(IWriteOnlyExactValueDescriptor descriptor) + { + IStateMember member = descriptor.StateMember; + + if (descriptor.Owner is Box) + { + _reader.ReadToFollowing(member.Name); + } + + string type = _reader.GetAttribute("Type"); + + Type instanceType = Type.GetType(type); + + // TODO: this will be the route method.. + descriptor.Route + (new MyCustomStateMember(descriptor.StateMember, + instanceType), descriptor.Owner, true); + } + + private T CreateObject + (IWriteOnlyValueDescriptor descriptor) + { + string type = _reader.GetAttribute("Type"); + + if (type != null) + { + Type instanceType = Type.GetType(type); + + T field = + (T) Activator.CreateInstance(instanceType); + + descriptor.Set(field); + + return field; + } + + return default(T); + } + + [ProcessorMethod] + public void ProcessInt32(IWriteOnlyExactValueDescriptor descriptor) + { + int value = _reader.ReadElementContentAsInt(); + descriptor.Set(value); + } + + [ProcessorMethod] + public void ProcessString(IWriteOnlyExactValueDescriptor descriptor) + { + string value = null; + + if (_reader.IsEmptyElement) + { + _reader.Read(); + } + else + { + value = _reader.ReadElementContentAsString(); + } + + descriptor.Set(value); + } + } +} \ No newline at end of file diff --git a/src/GraphClimber/Examples/Xml/XmlWriterProcessor.cs b/src/GraphClimber.ConsoleApp/Examples/Xml/XmlWriterProcessor.cs similarity index 88% rename from src/GraphClimber/Examples/Xml/XmlWriterProcessor.cs rename to src/GraphClimber.ConsoleApp/Examples/Xml/XmlWriterProcessor.cs index 561397e..df1b3e2 100644 --- a/src/GraphClimber/Examples/Xml/XmlWriterProcessor.cs +++ b/src/GraphClimber.ConsoleApp/Examples/Xml/XmlWriterProcessor.cs @@ -7,12 +7,10 @@ namespace GraphClimber.Examples public class XmlWriterProcessor : INullProcessor { private readonly XmlWriter _writer; - private StringWriter _stringWriter; - public XmlWriterProcessor() + public XmlWriterProcessor(XmlWriter writer) { - _stringWriter = new StringWriter(); - _writer = new XmlTextWriter(_stringWriter); + _writer = writer; } [ProcessorMethod] @@ -64,7 +62,6 @@ private void EndWritePropertyName() public void ProcessNull(IWriteOnlyValueDescriptor descriptor) { WritePropertyName(descriptor); - _writer.WriteValue("null"); EndWritePropertyName(); } } diff --git a/src/GraphClimber.ConsoleApp/GraphClimber.ConsoleApp.csproj b/src/GraphClimber.ConsoleApp/GraphClimber.ConsoleApp.csproj new file mode 100644 index 0000000..3135c38 --- /dev/null +++ b/src/GraphClimber.ConsoleApp/GraphClimber.ConsoleApp.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp3.1 + + + + + + + diff --git a/src/GraphClimber.ConsoleApp/Program.cs b/src/GraphClimber.ConsoleApp/Program.cs new file mode 100644 index 0000000..85930f5 --- /dev/null +++ b/src/GraphClimber.ConsoleApp/Program.cs @@ -0,0 +1,249 @@ +using System; +using System.IO; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Xml; +using System.Xml.Linq; +using GraphClimber.ConsoleApp.Examples.Binary; +using GraphClimber.Examples; +using GraphClimber.Examples.Binary; + +namespace GraphClimber +{ + enum Days + { + Sunday, + Monday, + Tuesday, + Wendensday, + Thursday, + Friday, + Saturday + } + + class SimpleType + { + + + public ValueType SomeValueType { get; set; } + + public string String { get; set; } + + public IConvertible Convertible { get; set; } + + + } + + public class Program + { + private static readonly IStateMemberProvider _stateMemberProvider = new CachingStateMemberProvider(new PropertyStateMemberProvider()); + + public static void DoSomething(StrongBox hello) + { + Console.WriteLine(hello); + } + + + static void Main(string[] args) + { + //ExpressionDebugGames.Play(); + IStore store = new TrivialStore(); + + store.Set("A", 5); + store.GetInner("A").Set("A", 10); + + SerializeDeserializeXML(); + + SerializeDeserializeStore(); + + SerializeDeserializeBinary(); + } + + public static object GetSimpleTypeInstance() + { + return new SimpleType() + { + Convertible = "sadasd", + SomeValueType = Days.Monday, + String = "Hello W0rld" + }; + } + + public class PersonHolder + { + public IPerson A { get; set; } + public IPerson B { get; set; } + + public IPerson C { get; set; } + } + + private static void SerializeDeserializeBinary() + { + BinaryFormatter formatter = new BinaryFormatter(); + + //object person = GetPerson(); + + IPerson structure = new Person2() { Age = 25, Surprise = Days.Monday }; + object person = new PersonHolder() { A = structure, B = structure, C = structure }; + + structure.IncreaseAge(); + + var stream = new MemoryStream(); + IWriter loggingWriter = new LoggingWriter(new CompressingWriter(new BinaryWriterAdapter(new BinaryWriter(stream))), Console.Out); + + formatter.Serialize(loggingWriter, person); + + stream.Position = 0; + IReader loggingReader = new LoggingReader(new DecompressingReader(new BinaryReaderAdapter(new BinaryReader(stream))), Console.Out); + + object deserialized = formatter.Deserialize(loggingReader); + } + + private static void SerializeDeserializeXML() + { + XmlSerializer serializer = new XmlSerializer(); + + var text = + @" + Shani Elharrar + 24 + + 23 + 4 + +"; + + // Writer code: + Person person = new Person() + { + Age = 24, + Name = "Shani Elharrar", + Surprise = new Person() + { + Age = 23, + Name = null, + Surprise = 4 + } + }; + + StringWriter stringWriter = new StringWriter(); + + serializer.Serialize(person, new XmlTextWriter(stringWriter)); + + string xml = stringWriter.ToString(); + + object result = serializer.Deserialize(XElement.Parse(xml)); + object result2 = serializer.Deserialize(XmlReader.Create(new StringReader(xml))); + } + + public struct MyClass + { + public string Name { get; set; } + } + + class Person + { + public Person() + { + //Children = new List(); + } + + public string Name { get; set; } + + public int Age { get; set; } + + public object Surprise { get; set; } + + public Person Father { get; set; } + + //public IList Children { get; set; } + } + + internal struct Person2 : IPerson + { + public string Name { get; set; } + + public int Age { get; set; } + + public object Surprise { get; set; } + + public object Father { get; set; } + + public Days Day { get; set; } + public void IncreaseAge() + { + Age++; + } + } + + + public static void SerializeDeserializeStore() + { + IStore store = new TrivialStore(); + StoreSerializer serializer = new StoreSerializer(); + + Person person = GetPerson(); + serializer.Write(person, store); + + object copy = serializer.Read(store); + } + + private static Person GetPerson() + { + var ilan = new Person { Age = 26 + 25, Name = "Ilan Zelingher", Surprise = 1 }; + ilan.Surprise = ilan; + return new Person() + { + Age = 26, + Name = "Elad Zelinger", + Father = ilan, + //Children = { new Person() { Name = "Jason"}, new Person() { Name = "Tomerh" }}, + Surprise = new Person() + { + Age = 21, + Name = "Yosi Attias", + Surprise = new MyClass() + { + Name = "YO!" + } + } + }; + } + + private static Person2 GetPerson2() + { + Person2 ilan = new Person2 { Age = 26 + 25, Name = "Ilan Zelingher" }; + + ilan.Surprise = ilan; + return new Person2() + { + Age = 26, + Name = "Elad Zelinger", + Father = ilan, + Day = Days.Tuesday, + Surprise = new Person2() + { + Age = 21, + Name = "Yosi Attias", + Surprise =ilan + //new object[] + //{ + // ilan, ilan, 342, "Hello", + // new int[,]{{1,1},{2,3},{5,8}}, + // new int[]{1,1,2,3,5,8}, + // Days.Saturday + //} + } + }; + + } + } + + public interface IPerson + { + + void IncreaseAge(); + + } +} \ No newline at end of file diff --git a/src/GraphClimber.Debug/ExpressionCompiler/CSharpExpressionDescriber.cs b/src/GraphClimber.Debug/ExpressionCompiler/CSharpExpressionDescriber.cs deleted file mode 100644 index eb83805..0000000 --- a/src/GraphClimber.Debug/ExpressionCompiler/CSharpExpressionDescriber.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.IO; -using System.Linq.Expressions; -using GraphClimber.ExpressionCompiler; -using Mono.Linq.Expressions; - -namespace GraphClimber.Debug.ExpressionCompiler -{ - public class CSharpExpressionDescriber : IExpressionDescriber - { - public static readonly IExpressionDescriber Empty = new CSharpExpressionDescriber(); - - private CSharpExpressionDescriber() - { - - } - - public string Describe(Expression expression) - { - var stringWriter = new StringWriter(); - var csharpWriter = new CSharpWriter(new TextFormatter(stringWriter)); - - csharpWriter.Write(expression); - - return stringWriter.ToString(); - } - } -} \ No newline at end of file diff --git a/src/GraphClimber.Debug/GraphClimber.Debug.csproj b/src/GraphClimber.Debug/GraphClimber.Debug.csproj deleted file mode 100644 index 6ab3bfe..0000000 --- a/src/GraphClimber.Debug/GraphClimber.Debug.csproj +++ /dev/null @@ -1,66 +0,0 @@ - - - - - Debug - AnyCPU - {B003B6BA-6A13-403E-8C1E-D26AE60C58A0} - Library - Properties - GraphClimber.Debug - GraphClimber.Debug - v4.5 - 512 - - - true - full - false - ..\..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\bin\Release\ - TRACE - prompt - 4 - true - - - - ..\packages\Mono.Linq.Expressions.1.2.0.0\lib\Mono.Linq.Expressions.dll - - - - - - - - - - - - - - - - {f7fa4635-c6c6-4d82-b344-b737438e1651} - GraphClimber - - - - - - - - \ No newline at end of file diff --git a/src/GraphClimber.Debug/Properties/AssemblyInfo.cs b/src/GraphClimber.Debug/Properties/AssemblyInfo.cs deleted file mode 100644 index 4538988..0000000 --- a/src/GraphClimber.Debug/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("GraphClimber.Debug")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("GraphClimber.Debug")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("8e268eed-bd81-4354-be31-618dd525e6fa")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/GraphClimber.Debug/packages.config b/src/GraphClimber.Debug/packages.config deleted file mode 100644 index 7c2d45b..0000000 --- a/src/GraphClimber.Debug/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/GraphClimber.Tests/GraphClimber.Tests.csproj b/src/GraphClimber.Tests/GraphClimber.Tests.csproj index 34530ae..423f3aa 100644 --- a/src/GraphClimber.Tests/GraphClimber.Tests.csproj +++ b/src/GraphClimber.Tests/GraphClimber.Tests.csproj @@ -1,70 +1,19 @@ - - - + + - Debug - AnyCPU - {99B3FD79-4D4B-4536-9F6B-2F53E86F8603} - Library - Properties - GraphClimber.Tests - GraphClimber.Tests - v4.5 - 512 - 00cceabe + netcoreapp3.1 + + false - - true - full - false - ..\..\bin\Debug\Tests\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\bin\Release\Tests\ - TRACE - prompt - 4 - - - - False - ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - - - - - - - - - - - - - - + - - {f7fa4635-c6c6-4d82-b344-b737438e1651} - GraphClimber - + + + + - + - - - \ No newline at end of file + + diff --git a/src/GraphClimber.Tests/Properties/AssemblyInfo.cs b/src/GraphClimber.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index c5a809b..0000000 --- a/src/GraphClimber.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("GraphClimber.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("GraphClimber.Tests")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("99b3fd79-4d4b-4536-9f6b-2f53e86f8603")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/GraphClimber.Tests/packages.config b/src/GraphClimber.Tests/packages.config deleted file mode 100644 index c714ef3..0000000 --- a/src/GraphClimber.Tests/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/GraphClimber.sln b/src/GraphClimber.sln index ad77fe3..59ac61a 100644 --- a/src/GraphClimber.sln +++ b/src/GraphClimber.sln @@ -1,13 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30011.22 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber", "GraphClimber\GraphClimber.csproj", "{F7FA4635-C6C6-4D82-B344-B737438E1651}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphClimber", "GraphClimber\GraphClimber.csproj", "{BD78BB49-71BF-4CFA-8DAE-E178623C225D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber.Tests", "GraphClimber.Tests\GraphClimber.Tests.csproj", "{99B3FD79-4D4B-4536-9F6B-2F53E86F8603}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber.Tests", "GraphClimber.Tests\GraphClimber.Tests.csproj", "{1CE9D582-AD82-4D61-B6D1-85AFF6288841}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber.Debug", "GraphClimber.Debug\GraphClimber.Debug.csproj", "{B003B6BA-6A13-403E-8C1E-D26AE60C58A0}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber.ConsoleApp", "GraphClimber.ConsoleApp\GraphClimber.ConsoleApp.csproj", "{5686D351-394B-4D2B-A06D-5A3FF1C5108B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,20 +15,23 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7FA4635-C6C6-4D82-B344-B737438E1651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7FA4635-C6C6-4D82-B344-B737438E1651}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7FA4635-C6C6-4D82-B344-B737438E1651}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7FA4635-C6C6-4D82-B344-B737438E1651}.Release|Any CPU.Build.0 = Release|Any CPU - {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Release|Any CPU.Build.0 = Release|Any CPU - {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Release|Any CPU.Build.0 = Release|Any CPU + {BD78BB49-71BF-4CFA-8DAE-E178623C225D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD78BB49-71BF-4CFA-8DAE-E178623C225D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD78BB49-71BF-4CFA-8DAE-E178623C225D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD78BB49-71BF-4CFA-8DAE-E178623C225D}.Release|Any CPU.Build.0 = Release|Any CPU + {1CE9D582-AD82-4D61-B6D1-85AFF6288841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CE9D582-AD82-4D61-B6D1-85AFF6288841}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CE9D582-AD82-4D61-B6D1-85AFF6288841}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CE9D582-AD82-4D61-B6D1-85AFF6288841}.Release|Any CPU.Build.0 = Release|Any CPU + {5686D351-394B-4D2B-A06D-5A3FF1C5108B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5686D351-394B-4D2B-A06D-5A3FF1C5108B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5686D351-394B-4D2B-A06D-5A3FF1C5108B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5686D351-394B-4D2B-A06D-5A3FF1C5108B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8D0DC358-E9C0-426C-BD72-7EFD69F49DB5} + EndGlobalSection EndGlobal diff --git a/src/GraphClimber.sln.DotSettings b/src/GraphClimber.sln.DotSettings index 0a046fc..d212b7d 100644 --- a/src/GraphClimber.sln.DotSettings +++ b/src/GraphClimber.sln.DotSettings @@ -1,3 +1,3 @@  <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> \ No newline at end of file + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> \ No newline at end of file diff --git a/src/GraphClimber/.vs/GraphClimber/DesignTimeBuild/.dtbcache.v2 b/src/GraphClimber/.vs/GraphClimber/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000..6d1d6c8 Binary files /dev/null and b/src/GraphClimber/.vs/GraphClimber/DesignTimeBuild/.dtbcache.v2 differ diff --git a/src/GraphClimber/App.config b/src/GraphClimber/App.config deleted file mode 100644 index fe04a3a..0000000 --- a/src/GraphClimber/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/GraphClimber/CachingStateMemberProvider.cs b/src/GraphClimber/CachingStateMemberProvider.cs new file mode 100644 index 0000000..b6cbd2e --- /dev/null +++ b/src/GraphClimber/CachingStateMemberProvider.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using GraphClimber.ValueDescriptor; + +namespace GraphClimber +{ + public class CachingStateMemberProvider : IStateMemberProvider + { + private readonly IStateMemberProvider _underlying; + + private readonly IDictionary> _cache = new Dictionary>(); + private readonly object _syncRoot = new object(); + + public CachingStateMemberProvider(IStateMemberProvider underlying) + { + _underlying = underlying; + } + + public IEnumerable Provide(Type type) + { + IEnumerable retVal; + if (_cache.TryGetValue(type, out retVal)) + { + return retVal; + } + + lock (_syncRoot) + { + if (!_cache.TryGetValue(type, out retVal)) + { + // ToList() is here to cache yield return methods. + _cache[type] = retVal = _underlying.Provide(type).ToList(); + } + } + + return retVal; + } + + public IStateMember ProvideArrayMember(Type arrayType, int arrayLength) + { + return _underlying.ProvideArrayMember(arrayType, arrayLength); + } + } +} \ No newline at end of file diff --git a/src/GraphClimber/DescriptorExtensionMethods.cs b/src/GraphClimber/DescriptorExtensionMethods.cs index d442fe0..f9f10e7 100644 --- a/src/GraphClimber/DescriptorExtensionMethods.cs +++ b/src/GraphClimber/DescriptorExtensionMethods.cs @@ -4,227 +4,227 @@ namespace GraphClimber { - public static class DescriptorExtensionMethods - { - - public static void RouteRuntimeType(this IValueDescriptor descriptor, bool skipSpecialMethod = false) - { - RouteRuntimeType(descriptor, typeof (TRuntime), skipSpecialMethod); - } - - public static void RouteRuntimeType(this IValueDescriptor descriptor, Type runtimeType, - bool skipSpecialMethod = false) - { - descriptor.Route(descriptor.StateMember, runtimeType, descriptor.Owner, skipSpecialMethod); - } - - public static void RouteMemberType(this IValueDescriptor descriptor, bool skipSpecialMethod = false) - { - var memberType = typeof(TMember); - RouteMemberType(descriptor, memberType, skipSpecialMethod); - } - - public static void RouteMemberType(IValueDescriptor descriptor, Type memberType, bool skipSpecialMethod = false) - { - descriptor.Route(descriptor.StateMember.WithMemberType(memberType), memberType, descriptor.Owner, skipSpecialMethod); - } - - public static void RouteMemberType(this IValueDescriptor descriptor, string name, bool skipSpecialMethod = false) - { - var memberType = typeof(TMember); - RouteMemberType(descriptor, name, memberType, skipSpecialMethod); - } - - public static void RouteMemberType(IValueDescriptor descriptor, string name, Type memberType, - bool skipSpecialMethod = false) - { - descriptor.Route(descriptor.StateMember.WithMemberType(memberType).WithName(name), memberType, descriptor.Owner, - skipSpecialMethod); - } - } - - public static class StateMemberExtensions - { - - public static IStateMember WithName(this IStateMember stateMember, string name) - { - return new NamedStateMember(stateMember, name); - } - - public static IStateMember WithMemberType(this IStateMember stateMember, Type memberType) - { - return new MemberTypeStateMember(stateMember, memberType); - } - - private class NamedStateMember : IStateMember - { - private readonly IStateMember _underlying; - private readonly string _name; - - public NamedStateMember(IStateMember underlying, string name) - { - _underlying = underlying; - _name = name; - } - - public string Name - { - get { return _name; } - } - - public Type OwnerType - { - get { return _underlying.OwnerType; } - } - - public Type MemberType - { - get { return _underlying.MemberType; } - } - - public bool CanRead - { - get { return _underlying.CanRead; } - } - - public bool CanWrite - { - get { return _underlying.CanWrite; } - } - - public Expression GetGetExpression(Expression obj) - { - return _underlying.GetGetExpression(obj); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - return _underlying.GetSetExpression(obj, value); - } - - public bool IsArrayElement - { - get { return _underlying.IsArrayElement; } - } - - public int[] ElementIndex - { - get { return _underlying.ElementIndex; } - } - - protected bool Equals(NamedStateMember other) - { - return Equals(_underlying, other._underlying) && string.Equals(_name, other._name); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((NamedStateMember) obj); - } - - public override int GetHashCode() - { - unchecked - { - return ((_underlying != null ? _underlying.GetHashCode() : 0)*397) ^ (_name != null ? _name.GetHashCode() : 0); - } - } - } - - private class MemberTypeStateMember : IStateMember, IReflectionStateMember - { - private readonly IStateMember _underlying; - private readonly Type _memberType; - - public MemberTypeStateMember(IStateMember underlying, Type memberType) - { - _underlying = underlying; - _memberType = memberType; - } - - public string Name - { - get { return _underlying.Name; } - } - - public Type OwnerType - { - get { return _underlying.OwnerType; } - } - - public Type MemberType - { - get { return _memberType; } - } - - public bool CanRead - { - get { return _underlying.CanRead; } - } - - public bool CanWrite - { - get { return _underlying.CanWrite; } - } - - public Expression GetGetExpression(Expression obj) - { - return _underlying.GetGetExpression(obj); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - return _underlying.GetSetExpression(obj, value); - } - - public bool IsArrayElement - { - get { return _underlying.IsArrayElement; } - } - - public int[] ElementIndex - { - get { return _underlying.ElementIndex; } - } - - protected bool Equals(MemberTypeStateMember other) - { - return Equals(_underlying, other._underlying) && Equals(_memberType, other._memberType); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((MemberTypeStateMember) obj); - } - - public override int GetHashCode() - { - unchecked - { - return ((_underlying != null ? _underlying.GetHashCode() : 0)*397) ^ (_memberType != null ? _memberType.GetHashCode() : 0); - } - } - - public MemberInfo UnderlyingMemberInfo - { - get { return ((IReflectionStateMember)_underlying).UnderlyingMemberInfo; } - } - - public object GetValue(object owner) - { - throw new NotImplementedException(); - } - - public void SetValue(object owner, object value) - { - throw new NotImplementedException(); - } - } - } + //public static class DescriptorExtensionMethods + //{ + + // public static void RouteRuntimeType(this IValueDescriptor descriptor, bool skipSpecialMethod = false) + // { + // RouteRuntimeType(descriptor, typeof (TRuntime), skipSpecialMethod); + // } + + // public static void RouteRuntimeType(this IValueDescriptor descriptor, Type runtimeType, + // bool skipSpecialMethod = false) + // { + // descriptor.Route(descriptor.StateMember, runtimeType, descriptor.Owner, skipSpecialMethod); + // } + + // public static void RouteMemberType(this IValueDescriptor descriptor, bool skipSpecialMethod = false) + // { + // var memberType = typeof(TMember); + // RouteMemberType(descriptor, memberType, skipSpecialMethod); + // } + + // public static void RouteMemberType(IValueDescriptor descriptor, Type memberType, bool skipSpecialMethod = false) + // { + // descriptor.Route(descriptor.StateMember.WithMemberType(memberType), memberType, descriptor.Owner, skipSpecialMethod); + // } + + // public static void RouteMemberType(this IValueDescriptor descriptor, string name, bool skipSpecialMethod = false) + // { + // var memberType = typeof(TMember); + // RouteMemberType(descriptor, name, memberType, skipSpecialMethod); + // } + + // public static void RouteMemberType(IValueDescriptor descriptor, string name, Type memberType, + // bool skipSpecialMethod = false) + // { + // descriptor.Route(descriptor.StateMember.WithMemberType(memberType).WithName(name), memberType, descriptor.Owner, + // skipSpecialMethod); + // } + //} + + //public static class StateMemberExtensions + //{ + + // public static IStateMember WithName(this IStateMember stateMember, string name) + // { + // return new NamedStateMember(stateMember, name); + // } + + // public static IStateMember WithMemberType(this IStateMember stateMember, Type memberType) + // { + // return new MemberTypeStateMember(stateMember, memberType); + // } + + // private class NamedStateMember : IStateMember + // { + // private readonly IStateMember _underlying; + // private readonly string _name; + + // public NamedStateMember(IStateMember underlying, string name) + // { + // _underlying = underlying; + // _name = name; + // } + + // public string Name + // { + // get { return _name; } + // } + + // public Type OwnerType + // { + // get { return _underlying.OwnerType; } + // } + + // public Type MemberType + // { + // get { return _underlying.MemberType; } + // } + + // public bool CanRead + // { + // get { return _underlying.CanRead; } + // } + + // public bool CanWrite + // { + // get { return _underlying.CanWrite; } + // } + + // public Expression GetGetExpression(Expression obj) + // { + // return _underlying.GetGetExpression(obj); + // } + + // public Expression GetSetExpression(Expression obj, Expression value) + // { + // return _underlying.GetSetExpression(obj, value); + // } + + // public bool IsArrayElement + // { + // get { return _underlying.IsArrayElement; } + // } + + // public int[] ElementIndex + // { + // get { return _underlying.ElementIndex; } + // } + + // protected bool Equals(NamedStateMember other) + // { + // return Equals(_underlying, other._underlying) && string.Equals(_name, other._name); + // } + + // public override bool Equals(object obj) + // { + // if (ReferenceEquals(null, obj)) return false; + // if (ReferenceEquals(this, obj)) return true; + // if (obj.GetType() != this.GetType()) return false; + // return Equals((NamedStateMember) obj); + // } + + // public override int GetHashCode() + // { + // unchecked + // { + // return ((_underlying != null ? _underlying.GetHashCode() : 0)*397) ^ (_name != null ? _name.GetHashCode() : 0); + // } + // } + // } + + // private class MemberTypeStateMember : IStateMember, IReflectionStateMember + // { + // private readonly IStateMember _underlying; + // private readonly Type _memberType; + + // public MemberTypeStateMember(IStateMember underlying, Type memberType) + // { + // _underlying = underlying; + // _memberType = memberType; + // } + + // public string Name + // { + // get { return _underlying.Name; } + // } + + // public Type OwnerType + // { + // get { return _underlying.OwnerType; } + // } + + // public Type MemberType + // { + // get { return _memberType; } + // } + + // public bool CanRead + // { + // get { return _underlying.CanRead; } + // } + + // public bool CanWrite + // { + // get { return _underlying.CanWrite; } + // } + + // public Expression GetGetExpression(Expression obj) + // { + // return _underlying.GetGetExpression(obj); + // } + + // public Expression GetSetExpression(Expression obj, Expression value) + // { + // return _underlying.GetSetExpression(obj, value); + // } + + // public bool IsArrayElement + // { + // get { return _underlying.IsArrayElement; } + // } + + // public int[] ElementIndex + // { + // get { return _underlying.ElementIndex; } + // } + + // protected bool Equals(MemberTypeStateMember other) + // { + // return Equals(_underlying, other._underlying) && Equals(_memberType, other._memberType); + // } + + // public override bool Equals(object obj) + // { + // if (ReferenceEquals(null, obj)) return false; + // if (ReferenceEquals(this, obj)) return true; + // if (obj.GetType() != this.GetType()) return false; + // return Equals((MemberTypeStateMember) obj); + // } + + // public override int GetHashCode() + // { + // unchecked + // { + // return ((_underlying != null ? _underlying.GetHashCode() : 0)*397) ^ (_memberType != null ? _memberType.GetHashCode() : 0); + // } + // } + + // public MemberInfo UnderlyingMemberInfo + // { + // get { return ((IReflectionStateMember)_underlying).UnderlyingMemberInfo; } + // } + + // public object GetValue(object owner) + // { + // throw new NotImplementedException(); + // } + + // public void SetValue(object owner, object value) + // { + // throw new NotImplementedException(); + // } + // } + //} } diff --git a/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs b/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs deleted file mode 100644 index 5667553..0000000 --- a/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using GraphClimber.ExpressionCompiler.Extensions; - -namespace GraphClimber.ExpressionCompiler -{ - /// - /// An - /// that mutates expressions that calls non public members (Fields, Properties or Methods) - /// to use "reflection" accessors. - /// - /// This is usually used on expressions that compiled to dynamic assemblies, Because - /// in this type of compilation, They cannot access non public members. - /// - public class AccessPrivateFieldVisitor : ExpressionVisitor - { - private const BindingFlags BindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public; - - public static readonly ExpressionVisitor Empty = new AccessPrivateFieldVisitor(); - - /// - /// Gets the field value from the given instance - /// - /// - /// - /// The instance to get the field value from, Or null for static fields - /// - [DebuggerNonUserCode] - public static object GetFieldValue(string assemblyQualifiedName, string fieldName, object instance) - { - return GetType(assemblyQualifiedName).GetField(fieldName, BindingFlags).GetValue(instance); - } - - /// - /// Gets the property value from the given instance - /// - /// - /// - /// The instance to get the property value from, Or null for static properties - /// - [DebuggerNonUserCode] - public static object GetPropertyValue(string assemblyQualifiedName, string propertyName, object instance) - { - return GetType(assemblyQualifiedName).GetProperty(propertyName, BindingFlags).GetValue(instance); - } - - /// - /// Calls the method on the given instance and returns the value from the method - /// - /// - /// - /// - /// The instance to call the method on, Or null for static methods - /// - /// - [DebuggerNonUserCode] - public static object CallMethod(string assemblyQualifiedName, string methodName, string[] genericArgumentTypes, - object instance, - params object[] parameters) - { - var methodInfo = GetType(assemblyQualifiedName).GetMethod(methodName, BindingFlags); - - if (methodInfo.ContainsGenericParameters) - { - methodInfo = methodInfo.MakeGenericMethod(genericArgumentTypes.Select(GetType).ToArray()); - } - - return methodInfo.Invoke(instance, parameters); - } - - /// - /// Gets the given type or throws exception in case - /// it's not found. - /// - /// - /// - private static Type GetType(string assemblyQualifiedName) - { - var returnValue = Type.GetType(assemblyQualifiedName); - - if (returnValue == null) - { - throw new NullReferenceException( - string.Format("Could not load type with assembly qualified name : '{0}', Exception thrown by '{1}'.", - assemblyQualifiedName, typeof (AccessPrivateFieldVisitor))); - } - - return returnValue; - } - - protected override Expression VisitMethodCall(MethodCallExpression node) - { - if (!node.Method.IsPublic) - { - // In case of static methods, instance should be null. - var reflectionInstance = node.Object ?? ExpressionExtensions.Null; - - // In case of generic method, - // we create an array of the assembly qualified names of the generic arguments. - var genericArgumentTypes = node.Method.IsGenericMethod - ? (Expression)Expression.NewArrayInit(typeof(string), node.Method.GetGenericArguments().Select(t => t.AssemblyQualifiedName.Constant())) - : ExpressionExtensions.Null; - - return - Expression.Call(null, typeof(AccessPrivateFieldVisitor).GetMethod("CallMethod"), - node.Method.DeclaringType.AssemblyQualifiedName.Constant(), - node.Method.Name.Constant(), - genericArgumentTypes, - reflectionInstance, - Expression.NewArrayInit(typeof(object), node.Arguments)).Convert(node.Type); - } - - return base.VisitMethodCall(node); - } - - protected override Expression VisitMember(MemberExpression node) - { - var fieldInfo = node.Member as FieldInfo; - if (fieldInfo != null) - { - return VisitFieldMemberExpression(node, fieldInfo); - } - - var propertyInfo = node.Member as PropertyInfo; - if (propertyInfo != null) - { - return VisitPropertyMemberExpression(node, propertyInfo); - } - - - return base.VisitMember(node); - } - - private static Expression VisitFieldMemberExpression(MemberExpression node, FieldInfo fieldInfo) - { - FieldAttributes fieldAttributes = fieldInfo.Attributes; - - bool isPrivateField = fieldAttributes.HasFlag(FieldAttributes.Private) || - fieldAttributes.HasFlag(FieldAttributes.PrivateScope); - - if (isPrivateField) - { - var argument = node.Expression ?? ExpressionExtensions.Null; - - return Expression.Call(null, - typeof (AccessPrivateFieldVisitor).GetMethod("GetFieldValue"), - fieldInfo.DeclaringType.AssemblyQualifiedName.Constant(), - fieldInfo.Name.Constant(), - argument).Convert(node.Type); - } - - return node; - } - - private static Expression VisitPropertyMemberExpression(MemberExpression node, PropertyInfo propertyInfo) - { - bool isPrivate = - new[] {propertyInfo.GetGetMethod(true), propertyInfo.GetSetMethod(true)}.Where(m => m != null) - .Select(m => m.Attributes) - .Any(m => m.HasFlag(MethodAttributes.Private)); - - if (isPrivate) - { - var argument = node.Expression.Convert() ?? ExpressionExtensions.Null; - - return Expression.Call(null, - typeof (AccessPrivateFieldVisitor).GetMethod("GetPropertyValue"), - propertyInfo.DeclaringType.AssemblyQualifiedName.Constant(), - propertyInfo.Name.Constant(), - argument).Convert(node.Type); - } - - return node; - } - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/DebugExpressionCompiler.cs b/src/GraphClimber/ExpressionCompiler/DebugExpressionCompiler.cs deleted file mode 100644 index 0a911a8..0000000 --- a/src/GraphClimber/ExpressionCompiler/DebugExpressionCompiler.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.CompilerServices; - -namespace GraphClimber.ExpressionCompiler -{ - /// - /// An - /// That compiles methods into dynamic assemblies. - /// - /// Also it, Writes the expression description to temporary file and allows - /// debugging with normal IDE (e.g Visual Studio). - /// - public class DebugExpressionCompiler : IExpressionCompiler - { - private readonly IExpressionDescriber _expressionDescriber; - - public DebugExpressionCompiler(IExpressionDescriber expressionDescriber) - { - _expressionDescriber = expressionDescriber; - } - - public TDelegate Compile(Expression expression) - { - var dynamicType = GetDynamicTypeBuilder(); - var dynamicMethod = dynamicType.DefineMethod(expression.Name, MethodAttributes.Public | MethodAttributes.Static); - - var tempFileName = Path.GetTempFileName(); - - File.AppendAllText(tempFileName, _expressionDescriber.Describe(expression)); - - var symbolDocument = Expression.SymbolDocument(tempFileName); - - var finalExpression = MutateLambdaExpression(expression, symbolDocument); - - CompileToMethod(finalExpression, dynamicMethod); - - var newType = dynamicType.CreateType(); - - return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), newType.GetMethod(dynamicMethod.Name)); - } - - private static void CompileToMethod(Expression expression, - MethodBuilder dynamicMethod) - { - var gen = DebugInfoGenerator.CreatePdbGenerator(); - expression.CompileToMethod(dynamicMethod, gen); - } - - private Expression MutateLambdaExpression(Expression expression, - SymbolDocumentInfo symbolDocument) - { - Expression returnValue = GetVisitors(expression, symbolDocument) - .Aggregate(expression, (current, visitor) => visitor.Visit(current)); - - return (Expression)returnValue; - } - - private static TypeBuilder GetDynamicTypeBuilder() - { - var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("GraphClimber.RuntimeGenerated"), - AssemblyBuilderAccess.RunAndSave); - var dynamicModule = dynamicAssembly.DefineDynamicModule("DynamicModule", true); - var dynamicType = dynamicModule.DefineType("GeneratedType", TypeAttributes.Public); - return dynamicType; - } - - private ExpressionVisitor[] GetVisitors(Expression expression, SymbolDocumentInfo symbolDocument) - { - return new[] { new DebugExpressionVistor(symbolDocument, expression, _expressionDescriber), NonTrivialConstantVisitor.Empty, AccessPrivateFieldVisitor.Empty }; - } - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs b/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs deleted file mode 100644 index b1ec51e..0000000 --- a/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; - -namespace GraphClimber.ExpressionCompiler -{ - public class DebugExpressionVistor : ExpressionVisitor - { - private static readonly ICollection _untouchedExpressionTypes = new[] { typeof(ParameterExpression), typeof(ConstantExpression) }; - private static readonly ICollection _unsymboledExpressionTypes = new[] { typeof(BlockExpression), typeof(LambdaExpression), typeof(LoopExpression) }; - - private static readonly string[] _newLineSeperator = { Environment.NewLine }; - - private readonly SymbolDocumentInfo _symbolDocumentInfo; - private readonly IExpressionDescriber _expressionDescriber; - private readonly string _initialDebugView; - private int _currentIndex; - - public DebugExpressionVistor(SymbolDocumentInfo symbolDocumentInfo, Expression initialExpression, IExpressionDescriber expressionDescriber) - { - _symbolDocumentInfo = symbolDocumentInfo; - _expressionDescriber = expressionDescriber; - - _initialDebugView = _expressionDescriber.Describe(initialExpression); - } - - private bool ContainsType(IEnumerable types, object instance) - { - var type = instance.GetType(); - - return types.Any(currentType => currentType.IsAssignableFrom(type)); - } - - public override Expression Visit(Expression node) - { - if (node == null) - { - return null; - } - - // Untouched remains as they are - if (ContainsType(_untouchedExpressionTypes, node)) - { - return node; - } - - // Unsymboled is not symboled, the node children are. - if (ContainsType(_unsymboledExpressionTypes, node)) - { - return base.Visit(node); - } - - Range range = GetCurrentExpressionRange(node); - - // Still not sure why I have so many plus one. - Expression debugInfoExpression = Expression.DebugInfo(_symbolDocumentInfo, - range.Start.Line + 1, - range.Start.Column + 1, - range.End.Line + 1, - range.End.Column + 1); - - Expression innerExpression = base.Visit(node); - - return Expression.Block(debugInfoExpression, innerExpression); - } - - private Range GetCurrentExpressionRange(Expression node) - { - string debugView = _expressionDescriber.Describe(node); - string[] debugViewLines = debugView.Split(_newLineSeperator, StringSplitOptions.RemoveEmptyEntries); - string firstDebugViewLine = debugViewLines.First(); - - var newIndex = _initialDebugView.IndexOf(firstDebugViewLine, _currentIndex, StringComparison.Ordinal); - _currentIndex = newIndex; - - Position start = _initialDebugView.GetPosition(_currentIndex); - int spacing = _initialDebugView.Split(_newLineSeperator, StringSplitOptions.None)[start.Line].IndexOfNot(' '); - - Position end = _initialDebugView.GetPosition(_currentIndex + debugView.Length + (debugViewLines.Length - 1) * spacing); - - return new Range(start, end); - } - - private struct Range - { - private readonly T _start; - private readonly T _end; - - public Range(T start, T end) - { - _start = start; - _end = end; - } - - public T Start - { - get { return _start; } - } - - public T End - { - get { return _end; } - } - } - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/DebugViewExpressionDescriber.cs b/src/GraphClimber/ExpressionCompiler/DebugViewExpressionDescriber.cs deleted file mode 100644 index a0889c8..0000000 --- a/src/GraphClimber/ExpressionCompiler/DebugViewExpressionDescriber.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Linq.Expressions; -using System.Reflection; - -namespace GraphClimber.ExpressionCompiler -{ - /// - /// Implementation of - /// using the property "DebugView" of the expressions. - /// - /// This may not work if microsoft/mono changes the implementation - /// of "DebugView". - /// - public class DebugViewExpressionDescriber : IExpressionDescriber - { - public static readonly IExpressionDescriber Empty = new DebugViewExpressionDescriber(); - - private static readonly PropertyInfo _debugView = typeof(Expression).GetProperty("DebugView", BindingFlags.NonPublic | BindingFlags.Instance); - - /// - /// Private C'tor, Please use property to get the instance of . - /// - private DebugViewExpressionDescriber() - { - - } - - private static string GetDebugView(Expression expression) - { - return (string) _debugView.GetValue(expression); - } - - public string Describe(Expression expression) - { - return GetDebugView(expression); - } - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/IExpressionCompiler.cs b/src/GraphClimber/ExpressionCompiler/IExpressionCompiler.cs deleted file mode 100644 index e8fcdc6..0000000 --- a/src/GraphClimber/ExpressionCompiler/IExpressionCompiler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Linq.Expressions; - -namespace GraphClimber.ExpressionCompiler -{ - public interface IExpressionCompiler - { - TDelegate Compile(Expression expression); - } -} diff --git a/src/GraphClimber/ExpressionCompiler/IExpressionDescriber.cs b/src/GraphClimber/ExpressionCompiler/IExpressionDescriber.cs deleted file mode 100644 index a4fae01..0000000 --- a/src/GraphClimber/ExpressionCompiler/IExpressionDescriber.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Linq.Expressions; - -namespace GraphClimber.ExpressionCompiler -{ - /// - /// Represents an object that can transform expressions to their describing strings. - /// - /// E.g, Transform expression to C# code. - /// - public interface IExpressionDescriber - { - - string Describe(Expression expression); - - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/NonTrivialConstantVisitor.cs b/src/GraphClimber/ExpressionCompiler/NonTrivialConstantVisitor.cs deleted file mode 100644 index d70d6fd..0000000 --- a/src/GraphClimber/ExpressionCompiler/NonTrivialConstantVisitor.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; -using GraphClimber.ExpressionCompiler.Extensions; - -namespace GraphClimber.ExpressionCompiler -{ - public class NonTrivialConstantVisitor : ExpressionVisitor - { - private static readonly MethodInfo _getMethodInfo = typeof (NonTrivialConstantVisitor).GetMethod("Get", BindingFlags.Static | BindingFlags.Public); - - private static readonly IList _objects = new List(); - private static readonly object _syncRoot = new object(); - - public static readonly ExpressionVisitor Empty = new NonTrivialConstantVisitor(); - - private NonTrivialConstantVisitor() - { - - } - - public static object Get(int number) - { - return _objects[number]; - } - - public static int Add(object value) - { - lock (_syncRoot) - { - int objectNumber = _objects.Count; - - _objects.Add(value); - - return objectNumber; - } - } - - protected override Expression VisitConstant(ConstantExpression node) - { - if (node.Type.IsPrimitive || node.Type == typeof(string)) - { - return base.VisitConstant(node); - } - - // RuntimeType is internal, using Type instead. - if (node.Type.FullName == "System.RuntimeType") - { - return Expression.Constant(node.Value, typeof (Type)); - } - - int objectNumber = Add(node.Value); - - return Expression.Call(_getMethodInfo, objectNumber.Constant()).Convert(node.Type); - } - } -} diff --git a/src/GraphClimber/ExpressionCompiler/StringExtensions.cs b/src/GraphClimber/ExpressionCompiler/StringExtensions.cs deleted file mode 100644 index 7e95a4d..0000000 --- a/src/GraphClimber/ExpressionCompiler/StringExtensions.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; - -namespace GraphClimber.ExpressionCompiler -{ - public static class StringExtensions - { - - /// - /// Gets the cursor position (Column, Line) of the given index in the given string. - /// - /// - /// - /// - public static Position GetPosition(this string str, int index) - { - var column = index; - var newLineIndex = str.IndexOf(Environment.NewLine, StringComparison.Ordinal); - var newLines = 0; - - while (newLineIndex != -1 && newLineIndex < index) - { - newLines++; - column = index - newLineIndex - Environment.NewLine.Length; - newLineIndex = str.IndexOf(Environment.NewLine, newLineIndex + 1, StringComparison.Ordinal); - } - - return new Position(newLines, column); - } - - public static int IndexOfNot(this string str, char chr) - { - for (int i = 0; i < str.Length; i++) - { - if (str[i] != chr) - { - return i; - } - } - - return -1; - } - - public static string FirstLowerCase(this string str) - { - return str.Substring(0, 1).ToLowerInvariant() + str.Substring(1); - } - - } - - /// - /// Represents a position inside a string - /// - public struct Position - { - private readonly int _line; - private readonly int _column; - - public Position(int line, int column) - { - _line = line; - _column = column; - } - - /// - /// Gets the line of the position - /// - public int Line - { - get - { - return _line; - } - } - - /// - /// Gets the column of the position - /// - public int Column - { - get - { - return _column; - } - } - - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/TrivialExpressionCompiler.cs b/src/GraphClimber/ExpressionCompiler/TrivialExpressionCompiler.cs deleted file mode 100644 index f17733b..0000000 --- a/src/GraphClimber/ExpressionCompiler/TrivialExpressionCompiler.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -namespace GraphClimber.ExpressionCompiler -{ - public class TrivialExpressionCompiler : IExpressionCompiler - { - public TDelegate Compile(Expression expression) - { - return expression.Compile(); - } - } - - public class FallbackExpressionCompiler : IExpressionCompiler - { - private readonly IExpressionCompiler[] _compilers; - - public FallbackExpressionCompiler(params IExpressionCompiler[] compilers) - { - _compilers = compilers; - } - - public TDelegate Compile(Expression expression) - { - IList exceptions = null; - - foreach (var compiler in _compilers) - { - try - { - return compiler.Compile(expression); - } - catch (Exception e) - { - exceptions = exceptions ?? new List(); - exceptions.Add(e); - } - } - - throw new AggregateException("Could not compile expression with any of the compilers given. Exceptions are collected.", exceptions); - } - } -} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionCompiler/Extensions/ExpressionExtensions.cs b/src/GraphClimber/ExpressionExtensions.cs similarity index 77% rename from src/GraphClimber/ExpressionCompiler/Extensions/ExpressionExtensions.cs rename to src/GraphClimber/ExpressionExtensions.cs index e400a15..d2a1ecb 100644 --- a/src/GraphClimber/ExpressionCompiler/Extensions/ExpressionExtensions.cs +++ b/src/GraphClimber/ExpressionExtensions.cs @@ -1,12 +1,8 @@ using System; using System.Linq.Expressions; -namespace GraphClimber.ExpressionCompiler.Extensions +namespace GraphClimber { - /// - /// Provides extension methods to create - /// expressions easier. - /// internal static class ExpressionExtensions { @@ -62,7 +58,8 @@ public static Expression Convert(this Expression expression, Type newType) var unaryExpression = expression as UnaryExpression; if (unaryExpression != null) { - if (unaryExpression.NodeType == ExpressionType.Convert) + if (unaryExpression.NodeType == ExpressionType.Convert && + !unaryExpression.IsCustomConversion()) { return Convert(unaryExpression.Operand, newType); } @@ -71,5 +68,18 @@ public static Expression Convert(this Expression expression, Type newType) return Expression.Convert(expression, newType); } + private static bool IsCustomConversion(this UnaryExpression unaryExpression) + { + Type conversionType = unaryExpression.Type; + Type originalType = unaryExpression.Operand.Type; + + return !(conversionType.IsAssignableFrom(originalType) || + originalType.IsAssignableFrom(conversionType)); + } + + public static string FirstLowerCase(this string str) + { + return str.Substring(0, 1).ToLowerInvariant() + str.Substring(1); + } } -} +} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/AccessorFactory.cs b/src/GraphClimber/ExpressionImplementation/AccessorFactory.cs index 2632027..8651f76 100644 --- a/src/GraphClimber/ExpressionImplementation/AccessorFactory.cs +++ b/src/GraphClimber/ExpressionImplementation/AccessorFactory.cs @@ -1,52 +1,42 @@ using System; using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; -using GraphClimber.ExpressionCompiler; -using GraphClimber.ExpressionCompiler.Extensions; - namespace GraphClimber { internal class AccessorFactory : IAccessorFactory { - private readonly IExpressionCompiler _compiler; - - public AccessorFactory(IExpressionCompiler compiler) - { - _compiler = compiler; - } - - public Action GetSetter(IStateMember member) + public Action GetSetter(IStateMember member) { ParameterExpression instance = Expression.Parameter(typeof(object)); + ParameterExpression indices = Expression.Parameter(typeof(int[])); ParameterExpression value = Expression.Parameter(typeof(T)); - Expression> lambda = - Expression.Lambda> - (member.GetSetExpression(instance, value), + Expression> lambda = + Expression.Lambda> + (member.GetSetExpression(instance, indices, value), "Setter_" + member.Name, - new[] {instance, value}); + new[] {instance, indices, value}); - return _compiler.Compile(lambda); + return lambda.Compile(); } - public Func GetGetter(IStateMember member) + public Func GetGetter(IStateMember member) { ParameterExpression instance = Expression.Parameter(typeof(object)); + ParameterExpression indices = Expression.Parameter(typeof(int[])); - Expression> lambda = - Expression.Lambda> - (GetGetterExpression(member, instance), + Expression> lambda = + Expression.Lambda> + (GetGetterExpression(member, instance, indices), "Getter_" + member.Name, - new[] {instance}); + new[] {instance, indices}); - return _compiler.Compile(lambda); + return lambda.Compile(); } - private static Expression GetGetterExpression(IStateMember member, Expression instance) + private static Expression GetGetterExpression(IStateMember member, Expression instance, Expression indices) { // We need to convert to the type, since sometimes we fake the member type. - return member.GetGetExpression(instance).Convert(typeof(T)); + return member.GetGetExpression(instance, indices).Convert(typeof(T)); } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/ArrayStateMember.cs b/src/GraphClimber/ExpressionImplementation/ArrayStateMember.cs new file mode 100644 index 0000000..f95d80e --- /dev/null +++ b/src/GraphClimber/ExpressionImplementation/ArrayStateMember.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace GraphClimber +{ + internal class ArrayStateMember : IStateMember + { + private readonly Type _arrayType; + private readonly Type _arrayElementType; + private readonly int[] _indices; + private readonly int _arrayRank; + + public ArrayStateMember(Type arrayType, Type arrayElementType, int arrayRank) + { + _arrayType = arrayType; + _arrayElementType = arrayElementType; + _arrayRank = arrayRank; + } + + public string Name + { + get + { + return _arrayType.FullName; + } + } + + public Type OwnerType + { + get + { + return _arrayType; + } + } + + public Type MemberType + { + get + { + return _arrayElementType; + } + } + + public bool CanRead + { + get { return true; } + } + + public bool CanWrite + { + get { return true; } + } + + public Expression GetGetExpression(Expression obj, Expression indices) + { + Expression getExpression = ArrayAccess(obj, indices); + return getExpression; + } + + private Expression ArrayAccess(Expression obj, Expression indices) + { + IEnumerable indexAccess = + Enumerable.Range(0, _arrayRank) + .Select(x => Expression.ArrayIndex(indices, + Expression.Constant(x))); + + return Expression.ArrayAccess(obj.Convert(this._arrayType), indexAccess); + } + + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) + { + Expression arrayAccess = ArrayAccess(obj, indices); + return Expression.Assign(arrayAccess, value); + } + + public IEnumerable Aliases + { + get + { + yield break; + } + } + } +} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/ClimbDelegateFactory.cs b/src/GraphClimber/ExpressionImplementation/ClimbDelegateFactory.cs index ee3bbe7..a1f0e31 100644 --- a/src/GraphClimber/ExpressionImplementation/ClimbDelegateFactory.cs +++ b/src/GraphClimber/ExpressionImplementation/ClimbDelegateFactory.cs @@ -3,8 +3,6 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { @@ -14,16 +12,14 @@ internal class ClimbDelegateFactory private readonly IStateMemberProvider _stateMemberProvider; private readonly IMethodMapper _methodMapper; private readonly ClimbStore _climbStore; - private readonly IExpressionCompiler _compiler; private readonly CallProcessMutator _mutator; - public ClimbDelegateFactory(Type processorType, IStateMemberProvider stateMemberProvider, IMethodMapper methodMapper, ClimbStore climbStore, IExpressionCompiler compiler) + public ClimbDelegateFactory(Type processorType, IStateMemberProvider stateMemberProvider, IMethodMapper methodMapper, ClimbStore climbStore) { _processorType = processorType; _stateMemberProvider = stateMemberProvider; _methodMapper = methodMapper; _climbStore = climbStore; - _compiler = compiler; _mutator = new CallProcessMutator(_processorType, _methodMapper); } @@ -56,16 +52,7 @@ private ClimbDelegate CreateReferenceDelegate(Type runtimeType) foreach (IStateMember member in members) { - DescriptorWriter writer = new DescriptorWriter(_climbStore); - - DescriptorVariable descriptor = - writer.GetDescriptor(castedProcessor, owner, member, member.MemberType); - - Expression callProcessor = - _mutator.GetExpression(castedProcessor, owner, member, descriptor.Reference); - - descriptorVariables.Add(descriptor.Reference); - expressions.Add(descriptor.Declaration); + Expression callProcessor = CallProcessor(castedProcessor, owner, EmptyIndex.Constant, member, descriptorVariables, expressions); expressions.Add(callProcessor); } @@ -77,11 +64,34 @@ private ClimbDelegate CreateReferenceDelegate(Type runtimeType) "Climb_" + runtimeType.Name, new[] {processor, value}); - ClimbDelegate result = _compiler.Compile(lambda); + ClimbDelegate result = lambda.Compile(); return result; } + private Expression CallProcessor + (Expression castedProcessor, + Expression owner, + Expression indices, + IStateMember member, + List methodVariables, + List methodAssignments) + { + DescriptorWriter writer = new DescriptorWriter(_climbStore); + + DescriptorVariable descriptor = + writer.GetDescriptor(castedProcessor, owner, indices, member, member.MemberType, + _stateMemberProvider); + + Expression callProcessor = + _mutator.GetExpression(castedProcessor, owner, member, descriptor.Reference, indices); + + methodVariables.Add(descriptor.Reference); + methodAssignments.Add(descriptor.Declaration); + + return callProcessor; + } + private ClimbDelegate CreateArrayDelegate(Type runtimeType) { @@ -93,56 +103,87 @@ private ClimbDelegate CreateArrayDelegate(Type runtimeType) var ranks = runtimeType.GetArrayRank(); - var rankParameters = - Enumerable.Range(0, ranks).Select(r => Expression.Variable(typeof (int), "rank_" + r)).ToList(); + List variables = new List(); + List assignments = new List(); - var upperBoundParameters = - Enumerable.Range(0, ranks).Select(r => Expression.Variable(typeof (int), "upper_" + r)).ToList(); + //int[] indices = new int[ranks]; + ParameterExpression indicesArray = Expression.Variable(typeof(int[]), "arrayIndex"); + variables.Add(indicesArray); + assignments.Add(Expression.Assign(indicesArray, Expression.NewArrayBounds(typeof(int), ranks.Constant()))); + + IStateMember member = _stateMemberProvider.ProvideArrayMember(runtimeType, ranks); + + Expression callExpression = + CallProcessor(castedProcessor, owner, indicesArray, member, variables, assignments); - var assignRankParameters = new Expression[ranks]; - var assignUpperParameters = new Expression[ranks]; + var loop = LoopArrayBounds(ranks, indicesArray, owner, callExpression, variables, assignments); + + BlockExpression climbBody = + Expression.Block(variables, + assignments.Concat(new[] {loop})); + + Expression> lambda = + Expression.Lambda>(climbBody, + "Climb_" + runtimeType.Name, + new[] { processor, value }); + + ClimbDelegate result = lambda.Compile(); + + return result; + } + + private static Expression LoopArrayBounds + (int ranks, + ParameterExpression indicesArray, + Expression owner, + Expression callExpression, + List parameterExpressions, + List assignments) + { + var loopVariables = + Enumerable.Range(0, ranks).Select(r => Expression.ArrayAccess(indicesArray, Expression.Constant(r))).ToList(); + + var upperBoundParameters = + Enumerable.Range(0, ranks).Select(r => Expression.Variable(typeof(int), "upper_" + r)).ToList(); - Expression callExpression = Expression.Empty(); // TODO : Complete. for (int rank = ranks - 1; rank >= 0; rank--) { // Create a for loop from lowerBound to upperBound? - var breakTarget = Expression.Label("break"); - var continueTarget = Expression.Label("continue"); + var breakTarget = Expression.Label("break" + rank); + var continueTarget = Expression.Label("continue" + rank); + + // i_k = array.GetLowerBound(k) + var currentLoopVariableAssignment = + Expression.Assign(loopVariables[rank], + Expression.Call(owner, "GetLowerBound", null, + Expression.Constant(rank))); - assignRankParameters[rank] = Expression.Assign(rankParameters[rank], - Expression.Call(owner, "GetLowerBound", null, Expression.Constant(rank))); + // length_k = array.GetUpperBound(k) + var currentUpperBoundAssignment = Expression.Assign(upperBoundParameters[rank], + Expression.Call(owner, "GetUpperBound", null, + Expression.Constant(rank))); - assignUpperParameters[rank] = Expression.Assign(upperBoundParameters[rank], - Expression.Call(owner, "GetUpperBound", null, Expression.Constant(rank))); + assignments.Add(currentUpperBoundAssignment); var loopBody = Expression.Block( - Expression.IfThen( - Expression.Equal(upperBoundParameters[rank], rankParameters[rank]), - Expression.Goto(breakTarget)), - callExpression, - Expression.PostIncrementAssign(rankParameters[rank]), - Expression.Goto(continueTarget)); - - callExpression = Expression.Loop(loopBody, breakTarget, continueTarget); + Expression.IfThen( + Expression.GreaterThan(loopVariables[rank], upperBoundParameters[rank]), + Expression.Goto(breakTarget)), + callExpression, + Expression.PostIncrementAssign(loopVariables[rank]), + Expression.Goto(continueTarget)); + + callExpression = + Expression.Block(currentLoopVariableAssignment, + Expression.Loop(loopBody, breakTarget, continueTarget)); } - BlockExpression climbBody = - Expression.Block(rankParameters.Concat(upperBoundParameters), - assignRankParameters.Concat(assignUpperParameters).Concat(new[] {callExpression})); - - Expression> lambda = - Expression.Lambda>(climbBody, - "Climb_" + runtimeType.Name, - new[] { processor, value }); - - ClimbDelegate result = _compiler.Compile(lambda); - - return result; + parameterExpressions.AddRange(upperBoundParameters); - throw new NotImplementedException("CreateArrayDelegate is not implemented"); + return callExpression; } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/ClimbStore.cs b/src/GraphClimber/ExpressionImplementation/ClimbStore.cs index 73cd7dd..942c27c 100644 --- a/src/GraphClimber/ExpressionImplementation/ClimbStore.cs +++ b/src/GraphClimber/ExpressionImplementation/ClimbStore.cs @@ -1,10 +1,10 @@ using System; -using GraphClimber.ExpressionCompiler; namespace GraphClimber { internal class ClimbStore : IClimbStore { + private readonly IStateMemberProvider _stateMemberProvider; private readonly AccessorDelegateCache _setters = new AccessorDelegateCache(); private readonly AccessorDelegateCache _getters = new AccessorDelegateCache(); private readonly AccessorDelegateCache _boxSetters = new AccessorDelegateCache(); @@ -16,21 +16,22 @@ internal class ClimbStore : IClimbStore private readonly RouteDelegateFactory _routeFactory; private readonly ClimbDelegateFactory _climbFactory; - public ClimbStore(Type processorType, IStateMemberProvider stateMemberProvider, IMethodMapper methodMapper, IExpressionCompiler compiler) + public ClimbStore(Type processorType, IStateMemberProvider stateMemberProvider, IMethodMapper methodMapper) { - _accessorFactory = new AccessorFactory(compiler); - _routeFactory = new RouteDelegateFactory(processorType, methodMapper, this, compiler); - _climbFactory = new ClimbDelegateFactory(processorType, stateMemberProvider, methodMapper, this, compiler); + _stateMemberProvider = stateMemberProvider; + _accessorFactory = new AccessorFactory(); + _routeFactory = new RouteDelegateFactory(processorType, methodMapper, this); + _climbFactory = new ClimbDelegateFactory(processorType, stateMemberProvider, methodMapper, this); } - public Action GetSetter(IStateMember member) + public Action GetSetter(IStateMember member) { return _setters.GetOrAdd (member, key => _accessorFactory.GetSetter(key)); } - public Func GetGetter(IStateMember member) + public Func GetGetter(IStateMember member) { return _getters.GetOrAdd (member, @@ -41,7 +42,7 @@ public RouteDelegate GetRoute(IStateMember member, Type runtimeMemberType) { return _routes.GetOrAdd(member, runtimeMemberType, (memberKey, runtimeTypeKey) => - _routeFactory.GetRouteDelegate(memberKey, runtimeTypeKey)); + _routeFactory.GetRouteDelegate(memberKey, runtimeTypeKey, _stateMemberProvider)); } public ClimbDelegate GetClimb(Type runtimeType) diff --git a/src/GraphClimber/ExpressionImplementation/DefaultGraphClimber.cs b/src/GraphClimber/ExpressionImplementation/DefaultGraphClimber.cs index 210c0b5..046169a 100644 --- a/src/GraphClimber/ExpressionImplementation/DefaultGraphClimber.cs +++ b/src/GraphClimber/ExpressionImplementation/DefaultGraphClimber.cs @@ -1,14 +1,12 @@ -using GraphClimber.ExpressionCompiler; - -namespace GraphClimber +namespace GraphClimber { - class DefaultGraphClimber : IGraphClimber + public class DefaultGraphClimber : IGraphClimber { private readonly ClimbStore _climbStore; - public DefaultGraphClimber(IStateMemberProvider stateMemberProvider, IMethodMapper methodMapper, IExpressionCompiler expressionCompiler ) + private DefaultGraphClimber(IStateMemberProvider stateMemberProvider, IMethodMapper methodMapper) { - _climbStore = new ClimbStore(typeof (TProcessor), stateMemberProvider, methodMapper, expressionCompiler); + _climbStore = new ClimbStore(typeof (TProcessor), stateMemberProvider, methodMapper); } public void Climb(object parent, TProcessor processor) @@ -16,17 +14,17 @@ public void Climb(object parent, TProcessor processor) _climbStore.GetClimb(parent.GetType())(processor, parent); } - public void Route(IStateMember stateMember, object current, TProcessor processor, bool skipSpecialMethod) + public void Route(IStateMember stateMember, object current, TProcessor processor, bool skipSpecialMethod, + int[] elementIndex) { - _climbStore.GetRoute(stateMember, current.GetType())(processor, current, skipSpecialMethod); + _climbStore.GetRoute(stateMember, current.GetType())(processor, current, skipSpecialMethod, elementIndex); } public static IGraphClimber Create(IStateMemberProvider stateMemberProvider) { return new DefaultGraphClimber( stateMemberProvider, - new MethodMapper(), - new TrivialExpressionCompiler()); + new MethodMapper()); } } } diff --git a/src/GraphClimber/ExpressionImplementation/DelegateCache/ClimbDelegateCache.cs b/src/GraphClimber/ExpressionImplementation/DelegateCache/ClimbDelegateCache.cs index 3b100fb..3d20e9e 100644 --- a/src/GraphClimber/ExpressionImplementation/DelegateCache/ClimbDelegateCache.cs +++ b/src/GraphClimber/ExpressionImplementation/DelegateCache/ClimbDelegateCache.cs @@ -4,12 +4,12 @@ namespace GraphClimber { internal class ClimbDelegateCache : DelegateCache> { - public new TDelegate Get(Type fieldType, Type runtimeType) + public TDelegate Get(Type fieldType, Type runtimeType) { return base.Get(Tuple.Create(fieldType, runtimeType)); } - public new TDelegate GetOrAdd(Type fieldType, Type runtimeType, Func factory) + public TDelegate GetOrAdd(Type fieldType, Type runtimeType, Func factory) { Func, TDelegate> tupleFactory = tuple => factory(tuple.Item1, tuple.Item2); diff --git a/src/GraphClimber/ExpressionImplementation/DescriptorVariable.cs b/src/GraphClimber/ExpressionImplementation/DescriptorVariable.cs index 2ed46fa..ab9bf11 100644 --- a/src/GraphClimber/ExpressionImplementation/DescriptorVariable.cs +++ b/src/GraphClimber/ExpressionImplementation/DescriptorVariable.cs @@ -1,9 +1,9 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { @@ -12,7 +12,9 @@ internal class DescriptorVariable private readonly ParameterExpression _reference; private readonly BinaryExpression _descriptorDeclaration; - public DescriptorVariable(IClimbStore store, Expression processor, Expression owner, IStateMember member, Type runtimeType) + public DescriptorVariable(IClimbStore store, Expression processor, Expression owner, Expression indices, + IStateMember member, + Type runtimeType, IStateMemberProvider stateMemberProvider) { Type descriptorType = DescriptorExtensions.GetDescriptorType(member, runtimeType); @@ -22,7 +24,7 @@ public DescriptorVariable(IClimbStore store, Expression processor, Expression ow _reference = Expression.Variable(descriptorType, member.Name.FirstLowerCase() + "Descriptor" ); - object memberLocal = Activator.CreateInstance(memberLocalType, store, member); + object memberLocal = Activator.CreateInstance(memberLocalType, store, member, stateMemberProvider); ConstructorInfo constructor = descriptorType.GetConstructors().FirstOrDefault(); @@ -31,10 +33,11 @@ public DescriptorVariable(IClimbStore store, Expression processor, Expression ow NewExpression creation = Expression.New(constructor, - processor, - owner.Convert(ownerParameterType), - memberLocal.Constant(), - store.Constant()); + processor, + owner.Convert(ownerParameterType), + indices, + memberLocal.Constant(), + store.Constant()); BinaryExpression assign = Expression.Assign(_reference, creation); diff --git a/src/GraphClimber/ExpressionImplementation/DescriptorWriter.cs b/src/GraphClimber/ExpressionImplementation/DescriptorWriter.cs index 0e10042..5aa5c58 100644 --- a/src/GraphClimber/ExpressionImplementation/DescriptorWriter.cs +++ b/src/GraphClimber/ExpressionImplementation/DescriptorWriter.cs @@ -13,9 +13,11 @@ public DescriptorWriter(IClimbStore store) _store = store; } - public DescriptorVariable GetDescriptor(Expression processor, Expression owner, IStateMember member, Type runtimeType) + public DescriptorVariable GetDescriptor(Expression processor, Expression owner, Expression indices, + IStateMember member, + Type runtimeType, IStateMemberProvider stateMemberProvider) { - return new DescriptorVariable(_store, processor, owner, member, runtimeType); + return new DescriptorVariable(_store, processor, owner, indices, member, runtimeType, stateMemberProvider); } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/EmptyIndex.cs b/src/GraphClimber/ExpressionImplementation/EmptyIndex.cs new file mode 100644 index 0000000..6fbf82b --- /dev/null +++ b/src/GraphClimber/ExpressionImplementation/EmptyIndex.cs @@ -0,0 +1,11 @@ +using System.Linq.Expressions; + +namespace GraphClimber +{ + internal class EmptyIndex + { + public static readonly int[] Value = new int[0]; + + public static readonly Expression Constant = Value.Constant(); + } +} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/EnumConvert.cs b/src/GraphClimber/ExpressionImplementation/EnumConvert.cs new file mode 100644 index 0000000..48df970 --- /dev/null +++ b/src/GraphClimber/ExpressionImplementation/EnumConvert.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq.Expressions; + +namespace GraphClimber +{ + internal class EnumConvert + { + public static readonly Func ToUnderlying = GetToUnderlying(); + public static readonly Func ToEnum = GetToEnum(); + + private static Func GetToUnderlying() + { + return GetConvert(); + } + + private static Func GetToEnum() + { + return GetConvert(); + } + + + private static Func GetConvert() + { + var parameter = Expression.Parameter(typeof(TSource), "value"); + + Expression> lambda = + Expression.Lambda> + (Expression.Convert(parameter, typeof(TTarget)), + parameter); + + return lambda.Compile(); + } + } +} \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/EnumReadWriteDescriptor.cs b/src/GraphClimber/ExpressionImplementation/EnumReadWriteDescriptor.cs index 5735b56..0b677e9 100644 --- a/src/GraphClimber/ExpressionImplementation/EnumReadWriteDescriptor.cs +++ b/src/GraphClimber/ExpressionImplementation/EnumReadWriteDescriptor.cs @@ -1,19 +1,21 @@ using System; +using System.Collections.Generic; namespace GraphClimber { internal class EnumReadOnlyDescriptor : ReadOnlyDescriptor, IReadOnlyEnumExactValueDescriptor - where TRuntime : TField, IConvertible + where TRuntime : Enum, TField where TUnderlying : IConvertible { // TRuntime is Enum! public EnumReadOnlyDescriptor(object processor, - object owner, - MemberLocal member, - IClimbStore climbStore) - : base(processor, owner, member, climbStore) + object owner, + int[] elementIndex, + MemberLocal member, + IClimbStore climbStore) + : base(processor, owner, elementIndex, member, climbStore) { } @@ -29,14 +31,15 @@ internal class EnumWriteOnlyDescriptor : WriteOnlyDescriptor, IWriteOnlyEnumExactValueDescriptor where TUnderlying : IConvertible - where TField : IConvertible + where TField : Enum { // TField is Enum! public EnumWriteOnlyDescriptor(object processor, - object owner, - MemberLocal member, - IClimbStore climbStore) - : base(processor, owner, member, climbStore) + object owner, + int[] elementIndex, + MemberLocal member, + IClimbStore climbStore) + : base(processor, owner, elementIndex, member, climbStore) { } @@ -48,7 +51,7 @@ public void SetUnderlying(TUnderlying value) } public interface IEnumReadWriteExactValueDescriptor : IReadOnlyEnumExactValueDescriptor, IWriteOnlyEnumExactValueDescriptor - where TEnum : IConvertible + where TEnum : Enum, IConvertible where TUnderlying : IConvertible { } @@ -56,15 +59,16 @@ public interface IEnumReadWriteExactValueDescriptor : IReadO internal class EnumReadWriteDescriptor : ReadWriteDescriptor, IEnumReadWriteExactValueDescriptor - where TRuntime : TField, IConvertible + where TRuntime : Enum, TField where TUnderlying : IConvertible { // TRuntime is Enum! public EnumReadWriteDescriptor(object processor, - object owner, - MemberLocal member, - IClimbStore climbStore) - : base(processor, owner, member, climbStore) + object owner, + int[] elementIndex, + MemberLocal member, + IClimbStore climbStore) + : base(processor, owner, elementIndex, member, climbStore) { } diff --git a/src/GraphClimber/ExpressionImplementation/EnumUnderlyingStateMember.cs b/src/GraphClimber/ExpressionImplementation/EnumUnderlyingStateMember.cs index 92bf935..5f77e0e 100644 --- a/src/GraphClimber/ExpressionImplementation/EnumUnderlyingStateMember.cs +++ b/src/GraphClimber/ExpressionImplementation/EnumUnderlyingStateMember.cs @@ -1,11 +1,11 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { - internal class EnumUnderlyingStateMember : IStateMember, IReflectionStateMember + internal class EnumUnderlyingStateMember : IStateMember { private readonly IStateMember _underlying; @@ -39,24 +39,22 @@ public bool CanWrite get { return _underlying.CanWrite; } } - public Expression GetGetExpression(Expression obj) + public Expression GetGetExpression(Expression obj, Expression indices) { - return _underlying.GetGetExpression(obj).Convert(MemberType); + return _underlying.GetGetExpression(obj, indices).Convert(MemberType); } - public Expression GetSetExpression(Expression obj, Expression value) + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) { - return _underlying.GetSetExpression(obj, value.Convert(_underlying.MemberType)); + return _underlying.GetSetExpression(obj, indices, value.Convert(_underlying.MemberType)); } - public bool IsArrayElement + public IEnumerable Aliases { - get { return _underlying.IsArrayElement; } - } - - public int[] ElementIndex - { - get { return _underlying.ElementIndex; } + get + { + yield return Name; + } } protected bool Equals(EnumUnderlyingStateMember other) @@ -76,46 +74,5 @@ public override int GetHashCode() { return (_underlying != null ? _underlying.GetHashCode() : 0); } - - public MemberInfo UnderlyingMemberInfo - { - get - { - var underlying = _underlying as IReflectionStateMember; - - if (underlying != null) - { - return underlying.UnderlyingMemberInfo; - } - - throw new NotImplementedException(); - } - } - - public object GetValue(object owner) - { - var underlying = _underlying as IReflectionStateMember; - - if (underlying != null) - { - return underlying.GetValue(owner); - } - - throw new NotImplementedException(); - } - - public void SetValue(object owner, object value) - { - var underlying = _underlying as IReflectionStateMember; - - if (underlying != null) - { - underlying.SetValue(owner, value); - } - else - { - throw new NotImplementedException(); - } - } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/IAccessorFactory.cs b/src/GraphClimber/ExpressionImplementation/IAccessorFactory.cs index b81dc02..1a959dc 100644 --- a/src/GraphClimber/ExpressionImplementation/IAccessorFactory.cs +++ b/src/GraphClimber/ExpressionImplementation/IAccessorFactory.cs @@ -4,7 +4,7 @@ namespace GraphClimber { internal interface IAccessorFactory { - Action GetSetter(IStateMember member); - Func GetGetter(IStateMember member); + Action GetSetter(IStateMember member); + Func GetGetter(IStateMember member); } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/IClimbStore.cs b/src/GraphClimber/ExpressionImplementation/IClimbStore.cs index ba24f43..aa68623 100644 --- a/src/GraphClimber/ExpressionImplementation/IClimbStore.cs +++ b/src/GraphClimber/ExpressionImplementation/IClimbStore.cs @@ -4,8 +4,8 @@ namespace GraphClimber { internal interface IClimbStore { - Action GetSetter(IStateMember member); - Func GetGetter(IStateMember member); + Action GetSetter(IStateMember member); + Func GetGetter(IStateMember member); RouteDelegate GetRoute(IStateMember member, Type runtimeMemberType); ClimbDelegate GetClimb(Type runtimeType); } diff --git a/src/GraphClimber/ExpressionImplementation/IDescriptorWriter.cs b/src/GraphClimber/ExpressionImplementation/IDescriptorWriter.cs index c32bff7..15327e2 100644 --- a/src/GraphClimber/ExpressionImplementation/IDescriptorWriter.cs +++ b/src/GraphClimber/ExpressionImplementation/IDescriptorWriter.cs @@ -8,7 +8,9 @@ internal interface IDescriptorWriter DescriptorVariable GetDescriptor (Expression processor, Expression owner, + Expression indices, IStateMember member, - Type runtimeType); + Type runtimeType, + IStateMemberProvider stateMemberProvider); } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/MemberLocal.cs b/src/GraphClimber/ExpressionImplementation/MemberLocal.cs index 5f6cc90..a47b1bf 100644 --- a/src/GraphClimber/ExpressionImplementation/MemberLocal.cs +++ b/src/GraphClimber/ExpressionImplementation/MemberLocal.cs @@ -1,26 +1,33 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; namespace GraphClimber { internal class MemberLocal { - private readonly Lazy> _getter; - private readonly Lazy> _setter; + private readonly Lazy> _getter; + private readonly Lazy> _setter; private readonly Lazy> _climb; private readonly Lazy> _structClimb; private readonly IStateMember _member; + private readonly IStateMemberProvider _provider; + private readonly Lazy> _children; public MemberLocal(IClimbStore climbStore, - IStateMember member) + IStateMember member, + IStateMemberProvider provider) { _member = member; - - _getter = - new Lazy>(() => climbStore.GetGetter(member)); + _provider = provider; + + _getter = + new Lazy>(() => climbStore.GetGetter(member)); _setter = - new Lazy>(() => climbStore.GetSetter(member)); + new Lazy>(() => climbStore.GetSetter(member)); _climb = new Lazy> @@ -29,9 +36,11 @@ public MemberLocal(IClimbStore climbStore, _structClimb = new Lazy> (() => climbStore.GetClimb(typeof(TRuntime))); + + _children = GetChildrenLazy(typeof(TRuntime), provider); } - public Func Getter + public Func Getter { get { @@ -39,7 +48,7 @@ public Func Getter } } - public Action Setter + public Action Setter { get { @@ -70,5 +79,33 @@ public IStateMember Member return _member; } } + + public IReadOnlyDictionary Children + { + get + { + return _children.Value; + } + } + + private Lazy> GetChildrenLazy(Type runtimeType, IStateMemberProvider memberProvider) + { + return new Lazy>(CreateChildrenDictionary); + + IReadOnlyDictionary CreateChildrenDictionary() => + new ReadOnlyDictionary(GetChildren() + .ToDictionary(x => x.alias, x => x.stateMember)); + + IEnumerable<(string alias, IStateMember stateMember)> GetChildren() + { + foreach (IStateMember stateMember in memberProvider.Provide(runtimeType)) + { + foreach (string alias in stateMember.Aliases ?? Enumerable.Empty()) + { + yield return (alias, stateMember); + } + } + } + } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/CallProcessMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/CallProcessMutator.cs index 40fa2df..d7b29a3 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/CallProcessMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/CallProcessMutator.cs @@ -19,9 +19,9 @@ public CallProcessMutator(Type processorType, IMethodMapper mapper) } public Expression GetExpression - (Expression processor, Expression owner, IStateMember member, Expression descriptor) + (Expression processor, Expression owner, IStateMember member, Expression descriptor, Expression indices) { - return _mutator.Mutate(Expression.Empty(), processor, owner, member, descriptor); + return _mutator.Mutate(Expression.Empty(), processor, owner, member, descriptor, indices); } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/CompositeMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/CompositeMutator.cs index 195e228..4aefaf7 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/CompositeMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/CompositeMutator.cs @@ -13,13 +13,14 @@ public CompositeMutator(IEnumerable mutators) _mutators = mutators; } - public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, Expression descriptor) + public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, + Expression descriptor, Expression indices) { Expression result = oldExpression; foreach (var mutator in _mutators) { - result = mutator.Mutate(result, processor, owner, member, descriptor); + result = mutator.Mutate(result, processor, owner, member, descriptor, indices); } return result; diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/IMethodMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/IMethodMutator.cs index 2ed0730..4fb4368 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/IMethodMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/IMethodMutator.cs @@ -5,9 +5,9 @@ namespace GraphClimber internal interface IMethodMutator { Expression Mutate(Expression oldExpression, - Expression processor, - Expression owner, - IStateMember member, - Expression descriptor); + Expression processor, + Expression owner, + IStateMember member, + Expression descriptor, Expression indices); } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/MethodCallMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/MethodCallMutator.cs index ddab165..b0964d8 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/MethodCallMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/MethodCallMutator.cs @@ -17,7 +17,8 @@ public MethodCallMutator(Type processorType, IMethodMapper methodMapper, bool ro _processorType = processorType; } - public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, Expression descriptor) + public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, + Expression descriptor, Expression indices) { MethodInfo methodToCall = _methodMapper.GetMethod(_processorType, member, member.MemberType, _routed); diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/NullProcessorMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/NullProcessorMutator.cs index bb48da9..2138d65 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/NullProcessorMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/NullProcessorMutator.cs @@ -1,7 +1,6 @@ using System; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { @@ -19,7 +18,8 @@ public NullProcessorMutator(Type processorType) _nullProcessorImplemented = typeof(INullProcessor).IsAssignableFrom(processorType); } - public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, Expression descriptor) + public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, + Expression descriptor, Expression indices) { if (!_nullProcessorImplemented) { @@ -49,7 +49,7 @@ public Expression Mutate(Expression oldExpression, Expression processor, Express // oldExpression(); // } - var value = member.GetGetExpression(owner); + var value = member.GetGetExpression(owner, indices); Expression body = Expression.Condition(Expression.Equal(value, ExpressionExtensions.Null), diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/PolymorphismMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/PolymorphismMutator.cs index 55b44a6..f6e3e09 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/PolymorphismMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/PolymorphismMutator.cs @@ -1,9 +1,6 @@ using System; -using System.Linq; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { @@ -16,7 +13,8 @@ internal class PolymorphismMutator : IMethodMutator private static readonly MethodInfo _getTypeMethod = Method.Get((object instance) => instance.GetType()); - public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, Expression descriptor) + public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, + Expression descriptor, Expression indices) { if (!member.CanRead) { @@ -34,7 +32,7 @@ public Expression Mutate(Expression oldExpression, Expression processor, Express var memberTypeConstant = memberType.Constant(); - var value = member.GetGetExpression(owner); + var value = member.GetGetExpression(owner, indices); var runtimeTypeAssign = Expression.Condition(Expression.Equal(value, ExpressionExtensions.Null), diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/RevisitedMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/RevisitedMutator.cs index 01fb68f..3749e24 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/RevisitedMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/RevisitedMutator.cs @@ -1,7 +1,6 @@ using System; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { @@ -25,7 +24,8 @@ public RevisitedMutator(Type processorType) _isRevisitedProcessor = typeof(IRevisitedProcessor).IsAssignableFrom(processorType); } - public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, Expression descriptor) + public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, + Expression descriptor, Expression indices) { if (!_isRevisitedFilter && !_isRevisitedProcessor) { @@ -53,7 +53,7 @@ public Expression Mutate(Expression oldExpression, Expression processor, Express // oldValue(); // } - var value = member.GetGetExpression(owner); + var value = member.GetGetExpression(owner, indices); Expression body = Expression.Condition(Expression.Call(processor, _visitedMethod, value), diff --git a/src/GraphClimber/ExpressionImplementation/Mutators/SpecialMethodMutator.cs b/src/GraphClimber/ExpressionImplementation/Mutators/SpecialMethodMutator.cs index 789f921..0feef1e 100644 --- a/src/GraphClimber/ExpressionImplementation/Mutators/SpecialMethodMutator.cs +++ b/src/GraphClimber/ExpressionImplementation/Mutators/SpecialMethodMutator.cs @@ -17,9 +17,10 @@ public SpecialMethodMutator(Type processorType) }); } - public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, Expression descriptor) + public Expression Mutate(Expression oldExpression, Expression processor, Expression owner, IStateMember member, + Expression descriptor, Expression indices) { - return _mutator.Mutate(oldExpression, processor, owner, member, descriptor); + return _mutator.Mutate(oldExpression, processor, owner, member, descriptor, indices); } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/PropertyStateMember.cs b/src/GraphClimber/ExpressionImplementation/PropertyStateMember.cs index 3d7ae61..1acee4a 100644 --- a/src/GraphClimber/ExpressionImplementation/PropertyStateMember.cs +++ b/src/GraphClimber/ExpressionImplementation/PropertyStateMember.cs @@ -1,14 +1,13 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { - internal class PropertyStateMember : IReflectionStateMember + internal class PropertyStateMember : IStateMember { private readonly PropertyInfo _property; - private static readonly int[] EmptyIndex = new int[0]; public PropertyStateMember(PropertyInfo property) { @@ -41,15 +40,15 @@ public bool CanWrite get { return _property.CanWrite; } } - public Expression GetGetExpression(Expression obj) + public Expression GetGetExpression(Expression obj, Expression indices) { return Expression.Property (obj.Convert(_property.DeclaringType), - _property); + _property); } - public Expression GetSetExpression(Expression obj, Expression value) + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) { Expression convertInstance; @@ -66,42 +65,20 @@ public Expression GetSetExpression(Expression obj, Expression value) return Expression.Assign(Expression.Property - (convertInstance, - _property), - value.Convert(_property.PropertyType)); + (convertInstance, + _property), + value.Convert(_property.PropertyType)); } - public bool IsArrayElement - { - get { return false; } - } - - public int[] ElementIndex - { - get - { - return EmptyIndex; - } - } - public MemberInfo UnderlyingMemberInfo + public IEnumerable Aliases { get { - return _property; + yield return Name; } } - public object GetValue(object owner) - { - return _property.GetValue(owner); - } - - public void SetValue(object owner, object value) - { - _property.SetValue(owner, value); - } - protected bool Equals(PropertyStateMember other) { return Equals(_property, other._property); diff --git a/src/GraphClimber/ExpressionImplementation/PropertyStateMemberProvider.cs b/src/GraphClimber/ExpressionImplementation/PropertyStateMemberProvider.cs index 370da85..f241443 100644 --- a/src/GraphClimber/ExpressionImplementation/PropertyStateMemberProvider.cs +++ b/src/GraphClimber/ExpressionImplementation/PropertyStateMemberProvider.cs @@ -5,7 +5,7 @@ namespace GraphClimber { - internal class PropertyStateMemberProvider : IStateMemberProvider + public class PropertyStateMemberProvider : IStateMemberProvider { public IEnumerable Provide(Type type) { @@ -14,9 +14,9 @@ public IEnumerable Provide(Type type) .Select(property => new PropertyStateMember(property)); } - public IStateMember ProvideArrayMember(Type arrayType, int[] indices) + public IStateMember ProvideArrayMember(Type arrayType, int arrayLength) { - return new ArrayStateMember(arrayType, arrayType.GetElementType(), indices); + return new ArrayStateMember(arrayType, arrayType.GetElementType(), arrayLength); } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/ReadOnlyDescriptor.cs b/src/GraphClimber/ExpressionImplementation/ReadOnlyDescriptor.cs index b0f7db1..a11732a 100644 --- a/src/GraphClimber/ExpressionImplementation/ReadOnlyDescriptor.cs +++ b/src/GraphClimber/ExpressionImplementation/ReadOnlyDescriptor.cs @@ -9,8 +9,10 @@ internal class ReadOnlyDescriptor : IReadOnlyExactValueDescriptor where TRuntime : TField { - public ReadOnlyDescriptor(object processor, object owner, MemberLocal member, IClimbStore climbStore) - : base(processor, owner, member, climbStore) + public ReadOnlyDescriptor(object processor, object owner, int[] elementIndex, + MemberLocal member, + IClimbStore climbStore) + : base(processor, owner, elementIndex, member, climbStore) { } diff --git a/src/GraphClimber/ExpressionImplementation/ReadWriteDescriptor.cs b/src/GraphClimber/ExpressionImplementation/ReadWriteDescriptor.cs index d500bab..24daea0 100644 --- a/src/GraphClimber/ExpressionImplementation/ReadWriteDescriptor.cs +++ b/src/GraphClimber/ExpressionImplementation/ReadWriteDescriptor.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; + namespace GraphClimber { internal class ReadWriteDescriptor : @@ -9,8 +12,10 @@ internal class ReadWriteDescriptor : IWriteOnlyValueDescriptor where TRuntime : TField { - public ReadWriteDescriptor(object processor, object owner, MemberLocal member, IClimbStore climbStore) : - base(processor, owner, member, climbStore) + public ReadWriteDescriptor(object processor, object owner, int[] elementIndex, + MemberLocal member, + IClimbStore climbStore) : + base(processor, owner, elementIndex, member, climbStore) { } diff --git a/src/GraphClimber/ExpressionImplementation/RouteDelegate.cs b/src/GraphClimber/ExpressionImplementation/RouteDelegate.cs index 107268e..b738039 100644 --- a/src/GraphClimber/ExpressionImplementation/RouteDelegate.cs +++ b/src/GraphClimber/ExpressionImplementation/RouteDelegate.cs @@ -1,4 +1,4 @@ namespace GraphClimber { - internal delegate void RouteDelegate(object processor, object owner, bool skipSpecialMethod); + internal delegate void RouteDelegate(object processor, object owner, bool skipSpecialMethod, int[] elementIndex); } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/RouteDelegateFactory.cs b/src/GraphClimber/ExpressionImplementation/RouteDelegateFactory.cs index 4965c57..5254116 100644 --- a/src/GraphClimber/ExpressionImplementation/RouteDelegateFactory.cs +++ b/src/GraphClimber/ExpressionImplementation/RouteDelegateFactory.cs @@ -1,33 +1,31 @@ using System; using System.Linq.Expressions; using System.Reflection; -using GraphClimber.ExpressionCompiler; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber { internal class RouteDelegateFactory { private readonly IClimbStore _climbStore; - private readonly IExpressionCompiler _compiler; private readonly Type _processorType; private readonly SpecialMethodMutator _specialMutator; private readonly IMethodMapper _methodMapper; - public RouteDelegateFactory(Type processorType, IMethodMapper methodMapper, IClimbStore climbStore, IExpressionCompiler compiler) + public RouteDelegateFactory(Type processorType, IMethodMapper methodMapper, IClimbStore climbStore) { _processorType = processorType; _climbStore = climbStore; _specialMutator = new SpecialMethodMutator(processorType); _methodMapper = methodMapper; - _compiler = compiler; } - public RouteDelegate GetRouteDelegate(IStateMember member, Type runtimeMemberType) + public RouteDelegate GetRouteDelegate(IStateMember member, Type runtimeMemberType, + IStateMemberProvider stateMemberProvider) { ParameterExpression processor = Expression.Parameter(typeof (object), "processor"); ParameterExpression owner = Expression.Parameter(typeof (object), "owner"); ParameterExpression skipSpecialMethods = Expression.Parameter(typeof (bool), "skipSpecialMethods"); + ParameterExpression elementIndex = Expression.Parameter(typeof(int[]), "elementIndex"); var castedProcessor = processor.Convert(_processorType); @@ -35,7 +33,7 @@ public RouteDelegate GetRouteDelegate(IStateMember member, Type runtimeMemberTyp DescriptorWriter descriptorWriter = new DescriptorWriter(_climbStore); DescriptorVariable descriptor = - descriptorWriter.GetDescriptor(processor, owner, member, runtimeMemberType); + descriptorWriter.GetDescriptor(processor, owner, elementIndex, member, runtimeMemberType, stateMemberProvider); MethodInfo methodToCall = _methodMapper.GetMethod(_processorType, member, runtimeMemberType, true); @@ -44,7 +42,8 @@ public RouteDelegate GetRouteDelegate(IStateMember member, Type runtimeMemberTyp Expression.Call(castedProcessor, methodToCall, descriptor.Reference); Expression callProcessWithSpecialMethods = - _specialMutator.Mutate(callProcess, castedProcessor, owner, member, descriptor.Reference); + _specialMutator.Mutate(callProcess, castedProcessor, owner, member, descriptor.Reference, + EmptyIndex.Constant); BlockExpression body = Expression.Block(new[] {descriptor.Reference}, @@ -56,9 +55,9 @@ public RouteDelegate GetRouteDelegate(IStateMember member, Type runtimeMemberTyp Expression lambda = Expression.Lambda(body, "Route_" + runtimeMemberType.Name, - new[] {processor, owner, skipSpecialMethods}); + new[] {processor, owner, skipSpecialMethods, elementIndex}); - return _compiler.Compile(lambda); + return lambda.Compile(); } } } \ No newline at end of file diff --git a/src/GraphClimber/ExpressionImplementation/ValueDescriptor.cs b/src/GraphClimber/ExpressionImplementation/ValueDescriptor.cs index 13c9f80..d91456d 100644 --- a/src/GraphClimber/ExpressionImplementation/ValueDescriptor.cs +++ b/src/GraphClimber/ExpressionImplementation/ValueDescriptor.cs @@ -1,21 +1,32 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; namespace GraphClimber { internal abstract class ValueDescriptor : IValueDescriptor where TRuntime : TField { + protected static readonly Lazy> _emptyDictionaryInitializer = + new Lazy> + (() => + new ReadOnlyDictionary(new Dictionary())); + private readonly MemberLocal _member; private readonly IClimbStore _climbStore; protected readonly object _owner; private readonly object _processor; private readonly bool _isStructMember; + private readonly int[] _elementIndex; - protected ValueDescriptor(object processor, object owner, MemberLocal member, IClimbStore climbStore) + protected ValueDescriptor(object processor, object owner, int[] elementIndex, + MemberLocal member, IClimbStore climbStore) { _owner = owner; _member = member; _climbStore = climbStore; + _elementIndex = elementIndex; _processor = processor; _isStructMember = Member.Member.OwnerType.IsValueType; } @@ -28,6 +39,14 @@ public IStateMember StateMember } } + public IReadOnlyDictionary Children + { + get + { + return _member.Children; + } + } + public object Owner { get @@ -36,6 +55,22 @@ public object Owner } } + public bool IsArrayElement + { + get + { + return ElementIndex.Length > 0; + } + } + + public int[] ElementIndex + { + get + { + return _elementIndex; + } + } + private IClimbStore ClimbStore { get @@ -77,11 +112,11 @@ protected void Climb(TField value) } else { - ClimReference(value, type); + ClimbReference(value, type); } } - private void ClimReference(TField value, Type type) + private void ClimbReference(TField value, Type type) { if (type == typeof(TRuntime)) { @@ -123,7 +158,7 @@ private void ClimbStruct(TField value, Type type) public void Route(IStateMember stateMember, Type runtimeMemberType, object owner, bool skipSpecialMethod) { RouteDelegate route = _climbStore.GetRoute(stateMember, runtimeMemberType); - route(_processor, owner, skipSpecialMethod); + route(_processor, owner, skipSpecialMethod, ElementIndex); } public void Route(IStateMember stateMember, object owner, bool skipSpecialMethod) @@ -133,12 +168,12 @@ public void Route(IStateMember stateMember, object owner, bool skipSpecialMethod public TRuntime Get() { - return (TRuntime) Member.Getter(Owner); + return (TRuntime) Member.Getter(Owner, ElementIndex); } public virtual void Set(TField value) { - Member.Setter(Owner, value); + Member.Setter(Owner, ElementIndex, value); } #region Enum Members diff --git a/src/GraphClimber/ExpressionImplementation/WriteOnlyDescriptor.cs b/src/GraphClimber/ExpressionImplementation/WriteOnlyDescriptor.cs index d024842..e502573 100644 --- a/src/GraphClimber/ExpressionImplementation/WriteOnlyDescriptor.cs +++ b/src/GraphClimber/ExpressionImplementation/WriteOnlyDescriptor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace GraphClimber { @@ -8,8 +9,10 @@ internal class WriteOnlyDescriptor : ValueDescriptor, IW private bool _setCalled; private TField _newValue; - public WriteOnlyDescriptor(object processor, object owner, MemberLocal member, IClimbStore climbStore) - : base(processor, owner, member, climbStore) + public WriteOnlyDescriptor(object processor, object owner, int[] elementIndex, + MemberLocal member, + IClimbStore climbStore) + : base(processor, owner, elementIndex, member, climbStore) { } diff --git a/src/GraphClimber/GraphClimber.csproj b/src/GraphClimber/GraphClimber.csproj index 7b7c688..dbdcea4 100644 --- a/src/GraphClimber/GraphClimber.csproj +++ b/src/GraphClimber/GraphClimber.csproj @@ -1,185 +1,7 @@ - - - + + - Debug - AnyCPU - {F7FA4635-C6C6-4D82-B344-B737438E1651} - Exe - Properties - GraphClimber - GraphClimber - v4.5 - 512 - 12.0.0 - 2.0 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true + netstandard2.0 - - AnyCPU - true - full - false - ..\..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - ..\..\bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - - \ No newline at end of file + + diff --git a/src/GraphClimber/IGraphClimber.cs b/src/GraphClimber/IGraphClimber.cs index d1adb6d..0386117 100644 --- a/src/GraphClimber/IGraphClimber.cs +++ b/src/GraphClimber/IGraphClimber.cs @@ -3,6 +3,7 @@ namespace GraphClimber public interface IGraphClimber { void Climb(object parent, TProcessor processor); - void Route(IStateMember stateMember, object current, TProcessor processor, bool skipSpecialMethod); + void Route(IStateMember stateMember, object current, TProcessor processor, bool skipSpecialMethod, + int[] elementIndex); } } \ No newline at end of file diff --git a/src/GraphClimber/IStateMember.cs b/src/GraphClimber/IStateMember.cs index 51ba94e..01334da 100644 --- a/src/GraphClimber/IStateMember.cs +++ b/src/GraphClimber/IStateMember.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; namespace GraphClimber @@ -38,24 +39,20 @@ public interface IStateMember /// /// An expression of the object that owns the field /// - Expression GetGetExpression(Expression obj); + Expression GetGetExpression(Expression obj, Expression indices); /// /// Gets the set expression to the state member /// /// An expression of the object that owns the field + /// /// The value to be set /// - Expression GetSetExpression(Expression obj, Expression value); + Expression GetSetExpression(Expression obj, Expression indices, Expression value); /// - /// Gets a value indicating whether this member is an array element. + /// Gets a list of aliases for this member. /// - bool IsArrayElement { get; } - - /// - /// Gets the index of this element in the array. - /// - int[] ElementIndex { get; } + IEnumerable Aliases { get; } } } \ No newline at end of file diff --git a/src/GraphClimber/IStateMemberProvider.cs b/src/GraphClimber/IStateMemberProvider.cs index d5cff7d..a83e9a9 100644 --- a/src/GraphClimber/IStateMemberProvider.cs +++ b/src/GraphClimber/IStateMemberProvider.cs @@ -19,6 +19,6 @@ public interface IStateMemberProvider IEnumerable Provide(Type type); // TODO: rethink about this one. - IStateMember ProvideArrayMember(Type arrayType, int[] indices); + IStateMember ProvideArrayMember(Type arrayType, int arrayLength); } } \ No newline at end of file diff --git a/src/GraphClimber/Program.cs b/src/GraphClimber/Program.cs deleted file mode 100644 index 5c2e3d4..0000000 --- a/src/GraphClimber/Program.cs +++ /dev/null @@ -1,385 +0,0 @@ -using System; -using System.IO; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Xml.Linq; -using GraphClimber.Examples; -using GraphClimber.Examples.Binary; -using GraphClimber.ExpressionCompiler; -using GraphClimber.ExpressionCompiler.Extensions; - -namespace GraphClimber -{ - internal class EnumConvert - { - public static readonly Func ToUnderlying = GetToUnderlying(); - public static readonly Func ToEnum = GetToEnum(); - - private static Func GetToUnderlying() - { - return GetConvert(); - } - - private static Func GetToEnum() - { - return GetConvert(); - } - - - private static Func GetConvert() - { - var parameter = Expression.Parameter(typeof(TSource), "value"); - - Expression> lambda = - Expression.Lambda> - (Expression.Convert(parameter, typeof (TTarget)), - parameter); - - return lambda.Compile(); - } - - } - - enum Days - { - Sunday, - Monday, - Tuesday, - Wendensday, - Thursday, - Friday, - Saturday - } - - public class ExpressionDebugGames - { - private static int PrivateField = 2; - - private static int PrivateProperty - { - get { return 5; } - } - - private static int PrivateMethod() - { - return 3; - } - - private static int GenericMethod(TEnum value) where TEnum : IConvertible - { - return 2; - } - - public static void Play() - { - - Expression> hi = () => typeof(int); - - MemberExpression propertyOrField = Expression.Field(null, typeof(ExpressionDebugGames).GetField("PrivateField", BindingFlags.Static | BindingFlags.NonPublic)); - MemberExpression property = Expression.Property(null, typeof(ExpressionDebugGames), "PrivateProperty"); - MethodCallExpression method = Expression.Call(null, - typeof(ExpressionDebugGames).GetMethod("PrivateMethod", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(typeof(object))); - - var parameter = Expression.Parameter(typeof(int), "someNumberArgument"); - - var variable = Expression.Variable(typeof(int), "myInt"); - var @break = Expression.Label(); - Expression exp = Expression.Assign(variable, Expression.Divide(propertyOrField, Expression.Subtract(property, method))); - exp = Expression.Block(new[] { variable }, exp, Expression.Add(2.Constant(), 5.Constant()), Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }), Expression.Constant("Hello Worlda"))); - - - var iVariable = Expression.Variable(typeof(int), "i"); - // exp = CustomExpression.For(iVariable, 0.Constant(), Expression.LessThan(iVariable, 5.Constant()), Expression.PostIncrementAssign(iVariable), exp); - - exp = Expression.Block(exp, - Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }), - Expression.Constant("Goodbye"))); - - var lambda = Expression.Lambda>(exp, "Hello_World", - new[] { parameter }); - - var expression = new DebugExpressionCompiler(DebugViewExpressionDescriber.Empty).Compile(lambda); - - expression(56); - } - - } - - class SimpleType - { - - - public ValueType SomeValueType { get; set; } - - public string String { get; set; } - - public IConvertible Convertible { get; set; } - - - } - - public class Program - { - private static readonly IStateMemberProvider _stateMemberProvider = new CachingStateMemberProvider(new ReflectionPropertyStateMemberProvider()); - - public static void DoSomething(StrongBox hello) - { - Console.WriteLine(hello); - } - - - static void Main(string[] args) - { - //ExpressionDebugGames.Play(); - //IStore store = new TrivialStore(); - - //store.Set("A", 5); - //store.GetInner("A").Set("A", 10); - - //SerializeDeserializeXML(); - - //SerializeDeserializeStore(); - - SerializeDeserializeBinary(); - } - - public static object GetSimpleTypeInstance() - { - return new SimpleType() - { - Convertible = "sadasd", - SomeValueType = Days.Monday, - String = "Hello W0rld" - }; - } - - public class PersonHolder - { - public IPerson A { get; set; } - public IPerson B { get; set; } - - public IPerson C { get; set; } - } - - private static void SerializeDeserializeBinary() - { - object person = GetSimpleTypeInstance(); - - IPerson structure = new Person2() { Age = 25, Surprise = Days.Monday }; - person = new PersonHolder() { A = structure, B = structure, C = structure }; - - structure.IncreaseAge(); - - //var stateMemberProvider = new BinaryStateMemberProvider(_stateMemberProvider); - var stateMemberProvider = new BinaryStateMemberProvider(new PropertyStateMemberProvider()); - - //var writeClimber = new SlowGraphClimber(stateMemberProvider); - //var readClimber = new SlowGraphClimber(stateMemberProvider); - - var stream = new MemoryStream(); - var binaryWriterProcessor = new BinaryWriterProcessor(new LoggingWriter(new CompressingWriter(new BinaryWriterAdapter(new BinaryWriter(stream))), Console.Out)); - - var writerGraphClimber = DefaultGraphClimber.Create(stateMemberProvider); - - //ClimbDelegate> climb2 = - // store2.GetClimb>(typeof(StrongBox)); - - //climb2(binaryWriterProcessor, - // new StrongBox(person)); - - writerGraphClimber.Climb(new StrongBox(person), binaryWriterProcessor); - - //writeClimber.Route(person, binaryWriterProcessor, false); - - stream.Position = 0; - var binaryReaderProcessor = new BinaryReaderProcessor(new LoggingReader(new DecompressingReader(new BinaryReaderAdapter(new BinaryReader(stream))), Console.Out)); - - var readerGraphClimber = DefaultGraphClimber.Create(stateMemberProvider); - var strongBox = new StrongBox(); - - readerGraphClimber.Climb(strongBox, binaryReaderProcessor); - - - //ClimbStore store = new ClimbStore(binaryReaderProcessor.GetType(), - // new BinaryStateMemberProvider(new PropertyStateMemberProvider()), - // new MethodMapper(), - // new TrivialExpressionCompiler()); - - //ClimbDelegate> climb = store.GetClimb>(typeof (StrongBox)); - - //climb(binaryReaderProcessor, strongBox); - } - - private static void SerializeDeserializeXML() - { - var text = - @" - Shani Elharrar - 24 - - null - 23 - 4 - -"; - - - // Reader code: - SlowGraphClimber climber2 = - new SlowGraphClimber - (_stateMemberProvider); - - XElement reader = XElement.Parse(text); - - XmlReaderProcessor processor2 = - new XmlReaderProcessor(reader); - - Person person2 = new Person(); - - climber2.Climb(person2, - processor2); - - - // Writer code: - SlowGraphClimber climber = - new SlowGraphClimber - (_stateMemberProvider); - - Person person = new Person() - { - Age = 24, - Name = "Shani Elharrar", - Surprise = new Person() - { - Age = 23, - Name = null, - Surprise = 4 - } - }; - - XmlWriterProcessor processor = new XmlWriterProcessor(); - - climber.Climb(person, - processor); - } - - public struct MyClass - { - public string Name { get; set; } - } - - class Person - { - public Person() - { - //Children = new List(); - } - - public string Name { get; set; } - - public int Age { get; set; } - - public object Surprise { get; set; } - - public Person Father { get; set; } - - //public IList Children { get; set; } - } - - internal struct Person2 : IPerson - { - public string Name { get; set; } - - public int Age { get; set; } - - public object Surprise { get; set; } - - public object Father { get; set; } - - public Days Day { get; set; } - public void IncreaseAge() - { - Age++; - } - } - - - public static void SerializeDeserializeStore() - { - var store = new TrivialStore(); - - SlowGraphClimber climber = new SlowGraphClimber(_stateMemberProvider); - - var processor = new StoreWriterProcessor(store); - var box = new StrongBox(GetPerson()); - - climber.Climb(box, processor); - - - SlowGraphClimber readerClimber = new SlowGraphClimber(_stateMemberProvider); - - var readerProcessor = new StoreReaderProcessor(store); - var readBox = new StrongBox(null); - readerClimber.Climb(readBox, readerProcessor); - - } - - private static Person GetPerson() - { - var ilan = new Person { Age = 26 + 25, Name = "Ilan Zelingher", Surprise = 1 }; - ilan.Surprise = ilan; - return new Person() - { - Age = 26, - Name = "Elad Zelinger", - Father = ilan, - //Children = { new Person() { Name = "Jason"}, new Person() { Name = "Tomerh" }}, - Surprise = new Person() - { - Age = 21, - Name = "Yosi Attias", - Surprise = new MyClass() - { - Name = "YO!" - } - } - }; - } - - private static Person2 GetPerson2() - { - Person2 ilan = new Person2 { Age = 26 + 25, Name = "Ilan Zelingher" }; - - ilan.Surprise = ilan; - return new Person2() - { - Age = 26, - Name = "Elad Zelinger", - Father = ilan, - Day = Days.Tuesday, - Surprise = new Person2() - { - Age = 21, - Name = "Yosi Attias", - Surprise =ilan - //new object[] - //{ - // ilan, ilan, 342, "Hello", - // new int[,]{{1,1},{2,3},{5,8}}, - // new int[]{1,1,2,3,5,8}, - // Days.Saturday - //} - } - }; - - } - } - - public interface IPerson - { - - void IncreaseAge(); - - } -} \ No newline at end of file diff --git a/src/GraphClimber/Properties/AssemblyInfo.cs b/src/GraphClimber/Properties/AssemblyInfo.cs deleted file mode 100644 index 56a3be0..0000000 --- a/src/GraphClimber/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("GraphClimber")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("CodeSharp")] -[assembly: AssemblyProduct("GraphClimber")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: InternalsVisibleTo("GraphClimber.Debug")] -[assembly: InternalsVisibleTo("GraphClimber.RuntimeGenerated")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f7fa4635-c6c6-4d82-b344-b737438e1651")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/GraphClimber/SlowGraphClimber.cs b/src/GraphClimber/SlowGraphClimber.cs deleted file mode 100644 index ddfff39..0000000 --- a/src/GraphClimber/SlowGraphClimber.cs +++ /dev/null @@ -1,797 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using GraphClimber.ValueDescriptor; - -namespace GraphClimber -{ - public class CachingStateMemberProvider : IStateMemberProvider - { - private readonly IStateMemberProvider _underlying; - - private readonly IDictionary> _cache = new Dictionary>(); - private readonly object _syncRoot = new object(); - - public CachingStateMemberProvider(IStateMemberProvider underlying) - { - _underlying = underlying; - } - - public IEnumerable Provide(Type type) - { - IEnumerable retVal; - if (_cache.TryGetValue(type, out retVal)) - { - return retVal; - } - - lock (_syncRoot) - { - if (!_cache.TryGetValue(type, out retVal)) - { - // ToList() is here to cache yield return methods. - _cache[type] = retVal = _underlying.Provide(type).ToList(); - } - } - - return retVal; - } - - public IStateMember ProvideArrayMember(Type arrayType, int[] indices) - { - // TODO : May not be smart performance wise. - return new ArrayStateMember(arrayType, arrayType.GetElementType(), indices); - } - } - - internal class ReflectionPropertyStateMemberProvider : IStateMemberProvider - { - public IEnumerable Provide(Type type) - { - return type.GetRuntimeProperties() - .Where(x => x.GetIndexParameters().Length == 0) - .Select(x => new ReflectionPropertyStateMember(x)); - } - - public IStateMember ProvideArrayMember(Type arrayType, int[] indices) - { - return new ArrayStateMember(arrayType, arrayType.GetElementType(), indices); - } - } - - - - internal class ReflectionPropertyStateMember : IReflectionStateMember - { - private readonly PropertyInfo _property; - - public ReflectionPropertyStateMember(PropertyInfo property) - { - _property = property; - } - - public string Name - { - get { return _property.Name; } - } - - public Type OwnerType - { - get { return _property.ReflectedType; } - } - - public virtual Type MemberType - { - get { return _property.PropertyType; } - } - - public bool CanRead - { - get { return _property.CanRead; } - } - - public bool CanWrite - { - get { return _property.CanWrite; } - } - - public Expression GetGetExpression(Expression obj) - { - throw new NotImplementedException(); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - throw new NotImplementedException(); - } - - public bool IsArrayElement - { - get { return false; } - } - - public int[] ElementIndex - { - get - { - // The empty index - return new int[0]; - } - } - - public MemberInfo UnderlyingMemberInfo - { - get - { - return _property; - } - } - - public object GetValue(object owner) - { - return _property.GetValue(owner); - } - - public void SetValue(object owner, object value) - { - _property.SetValue(owner, value); - } - } - - public interface IReflectionStateMember : IStateMember - { - MemberInfo UnderlyingMemberInfo { get; } - - object GetValue(object owner); - - void SetValue(object owner, object value); - } - - internal class ReflectionValueDescriptor : - IReadOnlyValueDescriptor, - IReadOnlyExactValueDescriptor, - IWriteOnlyExactValueDescriptor, - IWriteOnlyValueDescriptor, - IReadWriteValueDescriptor, - IReflectionValueDescriptor where - TRuntime : TField - { - private readonly IStateMemberProvider _stateMemberProvider; - private readonly IReflectionStateMember _stateMember; - private readonly object _owner; - private readonly object _processor; - - public ReflectionValueDescriptor(object processor, IStateMemberProvider stateMemberProvider, - IReflectionStateMember stateMember, object owner) - { - _stateMemberProvider = stateMemberProvider; - _stateMember = stateMember; - _owner = owner; - _processor = processor; - } - - public TField Get() - { - return (TField) _stateMember.GetValue(_owner); - } - - object IReflectionValueDescriptor.Get() - { - return Get(); - } - - TRuntime IReadOnlyValueDescriptor.Get() - { - return (TRuntime) Get(); - } - - TRuntime IReadOnlyExactValueDescriptor.Get() - { - IReadOnlyValueDescriptor casted = this; - return casted.Get(); - } - - public void Set(TField value) - { - _stateMember.SetValue(_owner, value); - } - - public IStateMember StateMember - { - get { return _stateMember; } - } - - public object Owner - { - get { return _owner; } - } - - public void Climb() - { - TField value = Get(); - - Type runtimeType; - - if (value != null) - { - runtimeType = value.GetType(); - } - else - { - throw new NullReferenceException("Can't climb on null, you silly developer!"); - } - - if (runtimeType.IsArray) - { - ClimbArray((Array) (object) value); - } - else - { - IEnumerable members = - _stateMemberProvider.Provide(runtimeType); - - object boxed = value; - - foreach (IReflectionStateMember member in - members.Cast()) - { - Type runtimeMemberType = GetRuntimeMemberType(member, value); - VisitMember(member, boxed, runtimeMemberType, false, false); - } - - if (runtimeType.IsValueType) - { - Set((TField) boxed); - } - } - } - - private void ClimbArray(Array array) - { - int dimension = array.Rank; - - IEnumerable> indexesSets = - Enumerable.Range(0, dimension) - .Select(index => Enumerable.Range(array.GetLowerBound(index), - array.GetLength(index))); - - IEnumerable> allIndexes = - Combinatorics.CartesianProduct(indexesSets.Reverse()); - - foreach (IEnumerable indexSet in allIndexes) - { - int[] indices = indexSet.Reverse().ToArray(); - - IReflectionStateMember decorated = (IReflectionStateMember) - _stateMemberProvider.ProvideArrayMember(array.GetType(), indices); - - Type runtimeMemberType = GetRuntimeMemberType(decorated, array); - - VisitMember(decorated, array, runtimeMemberType, false, false); - } - } - - private Type GetRuntimeMemberType(IReflectionStateMember member, object value) - { - Type memberType = member.MemberType; - - object memberValue = member.GetValue(value); - - var result = - memberValue != null ? memberValue.GetType() : memberType; - - return result; - } - - private void VisitMember(IReflectionStateMember member, - object owner, - Type runtimeMemberType, - bool skipSpecialMethod, - bool routed) - { - IReflectionValueDescriptor descriptor = - CreateDescriptor(member, owner, runtimeMemberType); - - CallProcess(descriptor, skipSpecialMethod, routed); - } - - private IReflectionValueDescriptor CreateDescriptor(IReflectionStateMember member, object value, - Type runtimeMemberType) - { - Type descriptorType; - - Type memberType = member.MemberType; - if (memberType.IsEnum) - { - descriptorType = typeof (ReflectionEnumValueDescriptor<,,>) - .MakeGenericType(memberType, runtimeMemberType, - memberType.GetEnumUnderlyingType()); - } - else - { - descriptorType = typeof(ReflectionValueDescriptor<,>) - .MakeGenericType(memberType, runtimeMemberType); - } - - IReflectionValueDescriptor descriptor = - (IReflectionValueDescriptor) Activator.CreateInstance - (descriptorType, - _processor, _stateMemberProvider, member, value); - - return descriptor; - } - - public void Route(IStateMember stateMember, object owner, bool skipSpecialMethod = true) - { - VisitMember((IReflectionStateMember) stateMember, - owner, - stateMember.MemberType, - skipSpecialMethod, true); - } - - public void Route(IStateMember stateMember, Type runtimeMemberType, object owner, bool skipSpecialMethod = true) - { - VisitMember((IReflectionStateMember) stateMember, - owner, - runtimeMemberType, - skipSpecialMethod, true); - } - - private void CallProcess(IReflectionValueDescriptor descriptor, bool skipSpecialMethod, bool routed) - { - Type fieldType = descriptor.StateMember.MemberType; - - bool methodCalled = false; - - if (!fieldType.IsValueType && !skipSpecialMethod) - { - methodCalled = TryCallSpecialMethod(descriptor, fieldType); - } - - if (!methodCalled) - { - CallMatchedProcess(descriptor, routed); - } - } - - private bool TryCallSpecialMethod(IReflectionValueDescriptor descriptor, Type fieldType) - { - object value = descriptor.Get(); - - INullProcessor processor = _processor as INullProcessor; - IRevisitedProcessor revisitedProcessor = _processor as IRevisitedProcessor; - - if (processor != null && value == null) - { - CallGenericMethod(descriptor, typeof (INullProcessor), fieldType, "ProcessNull"); - return true; - } - else if ((value != null) && - (revisitedProcessor != null) && - revisitedProcessor.Visited(value)) - { - CallGenericMethod(descriptor, typeof (IRevisitedProcessor), fieldType, "ProcessRevisited"); - return true; - } - - return false; - } - - private void CallGenericMethod(IReflectionValueDescriptor descriptor, Type processorType, Type genericType, string methodName) - { - MethodInfo methodToCall = - processorType.GetMethod(methodName) - .MakeGenericMethod(genericType); - - methodToCall.Invoke(_processor, new object[] {descriptor}); - } - - private void CallMatchedProcess(IReflectionValueDescriptor descriptor, bool routed) - { - GenericArgumentBinder binder = new GenericArgumentBinder(new FallbackToFirstCandidateMethodSelector(new BinderMethodSelector(Type.DefaultBinder))); - - IEnumerable methods = - _processor.GetType().GetMethods() - .Where(x => x.IsDefined(typeof (ProcessorMethodAttribute))) - .Where(x => !x.GetCustomAttribute().OnlyOnRoute || routed); - - Type descriptorType = descriptor.GetType(); - - IEnumerable> candidates = - methods.Select(method => Bind(binder, method, descriptorType)) - .Where(x => x != null) - .GroupBy(x => x.GetCustomAttribute().Precedence) - .OrderBy(x => x.Key); - - IGrouping maximum = candidates.FirstOrDefault(); - - if (maximum.Skip(1).Any()) - { - throw new Exception("Too many candidates for the processor thingy. Use precedence."); - } - else - { - MethodInfo method = maximum.FirstOrDefault(); - - if (method != null) - { - method.Invoke(_processor, new object[] {descriptor}); - } - else - { - throw new Exception( - "No method found :(, this might be a bug in your code, or in the GraphClimber. Good luck."); - } - } - } - - private MethodInfo Bind(GenericArgumentBinder binder, MethodInfo method, Type descriptorType) - { - MethodInfo bindedMethod; - - if (binder.TryBind(method, new[] {descriptorType}, out bindedMethod)) - { - return bindedMethod; - } - - return null; - } - } - - internal class ReflectionEnumValueDescriptor : - ReflectionValueDescriptor, - IReadOnlyEnumExactValueDescriptor, - IWriteOnlyEnumExactValueDescriptor - where TRuntime : TField - where TField : IConvertible - where TUnderlying : IConvertible - { - private readonly IStateMember _underlyingValueStateMember; - - public ReflectionEnumValueDescriptor(object processor, IStateMemberProvider stateMemberProvider, IReflectionStateMember stateMember, object owner) : - base(processor, stateMemberProvider, stateMember, owner) - { - _underlyingValueStateMember = new EnumUnderlyingValueStateMember(stateMember); - } - - public TUnderlying GetUnderlying() - { - TField result = Get(); - - TUnderlying value = - (TUnderlying) Convert.ChangeType(result, typeof (TUnderlying)); - - return value; - } - - public void SetUnderlying(TUnderlying value) - { - long asLong = - (long) Convert.ChangeType(value, typeof (long)); - - TField result = - (TField) Enum.ToObject(typeof (TField), asLong); - - Set(result); - } - - public IStateMember UnderlyingValueStateMember - { - get - { - return _underlyingValueStateMember; - } - } - } - - internal class EnumUnderlyingValueStateMember : IReflectionStateMember - { - private readonly IReflectionStateMember _stateMember; - private readonly Type _enumType; - private readonly Type _underlyingType; - - public EnumUnderlyingValueStateMember(IReflectionStateMember stateMember) - { - _stateMember = stateMember; - _enumType = _stateMember.MemberType; - _underlyingType = _enumType.GetEnumUnderlyingType(); - } - - public string Name - { - get { return _stateMember.Name; } - } - - public Type OwnerType - { - get { return _stateMember.OwnerType; } - } - - public Type MemberType - { - get { return _underlyingType; } - } - - public bool CanRead - { - get { return _stateMember.CanRead; } - } - - public bool CanWrite - { - get { return _stateMember.CanWrite; } - } - - public Expression GetGetExpression(Expression obj) - { - return _stateMember.GetGetExpression(obj); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - return _stateMember.GetSetExpression(obj, value); - } - - public bool IsArrayElement - { - get { return _stateMember.IsArrayElement; } - } - - public int[] ElementIndex - { - get { return _stateMember.ElementIndex; } - } - - public MemberInfo UnderlyingMemberInfo - { - get { return _stateMember.UnderlyingMemberInfo; } - } - - public object GetValue(object owner) - { - return Convert.ChangeType(_stateMember.GetValue(owner), _underlyingType); - } - - public void SetValue(object owner, object value) - { - // Thats how they do it :( - object casted = - Enum.ToObject(_enumType, Convert.ToInt64(value)); - - _stateMember.SetValue(owner, casted); - } - } - - internal class ArrayStateMember : IReflectionStateMember - { - private readonly Type _arrayType; - private readonly Type _arrayElementType; - private readonly int[] _indices; - - public ArrayStateMember(Type arrayType, Type arrayElementType, int[] indices) - { - _arrayType = arrayType; - _arrayElementType = arrayElementType; - _indices = indices; - } - - public string Name - { - get - { - return string.Format("[{0}]", - string.Join(", ", _indices)); - } - } - - public Type OwnerType - { - get - { - return _arrayType; - } - } - - public Type MemberType - { - get - { - return _arrayElementType; - } - } - - public bool CanRead - { - get { return true; } - } - - public bool CanWrite - { - get { return true; } - } - - public Expression GetGetExpression(Expression obj) - { - throw new NotImplementedException(); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - throw new NotImplementedException(); - } - - public bool IsArrayElement - { - get - { - return true; - } - } - - public int[] ElementIndex - { - get - { - return _indices; - } - } - - public MemberInfo UnderlyingMemberInfo - { - get { throw new NotImplementedException(); } - } - - public object GetValue(object owner) - { - Array array = owner as Array; - return array.GetValue(_indices); - } - - public void SetValue(object owner, object value) - { - Array array = owner as Array; - array.SetValue(value, _indices); - } - } - - internal interface IReflectionValueDescriptor : IValueDescriptor - { - object Get(); - } - - - public class SlowGraphClimber : IGraphClimber - { - private readonly IStateMemberProvider _stateMemberProvider; - - public SlowGraphClimber(IStateMemberProvider stateMemberProvider) - { - _stateMemberProvider = stateMemberProvider; - } - - public void Climb(object parent, TProcessor processor) - { - var descriptor = GetDescriptor(parent, processor); - - descriptor.Climb(); - } - - public void Route(IStateMember stateMember, object current, TProcessor processor, bool skipSpecialMethod) - { - throw new NotImplementedException(); - } - - public void Route(object current, TProcessor processor, bool skipSpecialMethod) - { - var descriptor = GetDescriptor(current, processor); - - descriptor.Route(descriptor.StateMember, current.GetType(), new Box { Parent = current }, skipSpecialMethod); - } - - - private ReflectionValueDescriptor GetDescriptor(object current, TProcessor processor) - { - var descriptor = - new ReflectionValueDescriptor(processor, - _stateMemberProvider, - new StaticStateMember(current), - null); - return descriptor; - } - - - private class Box - { - public object Parent { get; set; } - } - } - - /* - public class StaticValueDescriptor : IReadOnlyValueDescriptor, - IReadOnlyExactValueDescriptor, - IReadWriteValueDescriptor - { - private readonly object _current; - private readonly object _processor; - - public StaticValueDescriptor(object current, object processor) - { - _current = current; - _processor = processor; - throw new NotImplementedException(); - } - - public void Set(object value) - { - throw new NotImplementedException(); - } - - public object Get() - { - return _current; - } - - public IStateMember StateMember - { - get { return StaticStateMember.Empty; } - } - - public class StaticStateMember : IStateMember - { - public static readonly IStateMember Empty = new StaticStateMember(); - - private StaticStateMember() - { - - } - - - public string Name - { - get { return "InitialValue"; } - } - - public Type OwnerType - { - get { return typeof (object); } - } - - public Type MemberType - { - get { return typeof(object); } - } - - public Expression GetGetExpression(Expression obj) - { - throw new NotImplementedException(); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - throw new NotImplementedException(); - } - } - - public object Owner - { - get { throw new NotImplementedException(); } - } - - public void Climb() - { - throw new NotImplementedException(); - } - - public void Route(IStateMember stateMember, Type runtimeMemberType, object owner) - { - throw new NotImplementedException(); - } - - public void Route(IStateMember stateMember, object owner) - { - throw new NotImplementedException(); - } - }*/ -} \ No newline at end of file diff --git a/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs b/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs index 74f882d..321245c 100644 --- a/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs +++ b/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs @@ -1,12 +1,12 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; -using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber.ValueDescriptor { - public class StaticStateMember : IReflectionStateMember + public class StaticStateMember : IStateMember { private readonly object _value; private readonly string _name; @@ -42,43 +42,26 @@ public bool CanWrite get { return false; } } - public Expression GetGetExpression(Expression obj) + public Expression GetGetExpression(Expression obj, Expression indices) { return _value.Constant(); } - public Expression GetSetExpression(Expression obj, Expression value) + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) { return Expression.Empty(); } - public bool IsArrayElement - { - get { return false; } - } - - public int[] ElementIndex - { - get { throw new NotImplementedException(); } - } - - public MemberInfo UnderlyingMemberInfo - { - get { throw new NotImplementedException(); } - } - - public object GetValue(object owner) - { - return _value; - } - - public void SetValue(object owner, object value) + public IEnumerable Aliases { - // Does nothing! + get + { + yield return Name; + } } } - public class StrongBoxStateMember : IReflectionStateMember + public class StrongBoxStateMember : IStateMember { private readonly StrongBox _strongBox; private readonly string _name; @@ -114,12 +97,12 @@ public bool CanWrite get { return true; } } - public Expression GetGetExpression(Expression obj) + public Expression GetGetExpression(Expression obj, Expression indices) { throw new NotImplementedException(); } - public Expression GetSetExpression(Expression obj, Expression value) + public Expression GetSetExpression(Expression obj, Expression indices, Expression value) { throw new NotImplementedException(); } @@ -134,163 +117,13 @@ public int[] ElementIndex get { throw new NotImplementedException(); } } - public MemberInfo UnderlyingMemberInfo - { - get { throw new NotImplementedException(); } - } - - public object GetValue(object owner) - { - return _strongBox.Value; - } - - public void SetValue(object owner, object value) - { - _strongBox.Value = (T) value; - } - } - - public class DelegateStateMember : IReflectionStateMember - { - private readonly Type _memberType; - private readonly Func _getValue; - private readonly Action _setValue; - - public DelegateStateMember(Type memberType, Func getValue, Action setValue) - { - _memberType = memberType; - _getValue = getValue; - _setValue = setValue; - } - - - public string Name - { - get { return "Value"; } - } - - public Type OwnerType - { - get { throw new NotSupportedException(); } - } - - public Type MemberType - { - get { return _memberType; } - } - - public bool CanRead - { - get { return true; } - } - - public bool CanWrite - { - get { return true; } - } - - public Expression GetGetExpression(Expression obj) - { - return Expression.Invoke(_getValue.Constant()); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - return Expression.Invoke(_setValue.Constant(), value); - } - - public bool IsArrayElement - { - get { return false; } - } - - public int[] ElementIndex - { - get { throw new NotSupportedException(); } - } - - public MemberInfo UnderlyingMemberInfo - { - get { throw new NotImplementedException(); } - } - - public object GetValue(object owner) - { - return _getValue(); - } - - public void SetValue(object owner, object value) - { - _setValue(value); - } - - public static IReflectionStateMember Create(Type memberType, Func getValue, Action setValue) - { - return new DelegateStateMember(memberType, getValue, setValue); - } - - public static IReflectionStateMember Create(Func getValue, Action setValue) - { - return new SafeDelegateStateMember(getValue, setValue); - } - } - - public class SafeDelegateStateMember : IReflectionStateMember - { - private readonly Func _getValue; - private readonly Action _setValue; - - public SafeDelegateStateMember(Func getValue, Action setValue) + public IEnumerable Aliases { - _getValue = getValue; - _setValue = setValue; + get + { + yield return Name; + } } - - public string Name - { - get { return "Value"; } - } - - public Type OwnerType - { - get { throw new NotSupportedException(); } - } - - public Type MemberType - { - get { return typeof (T); } - } - - public bool CanRead - { - get { return true; } - } - - public bool CanWrite - { - get { return true; } - } - - public Expression GetGetExpression(Expression obj) - { - return Expression.Invoke(_getValue.Constant()); - } - - public Expression GetSetExpression(Expression obj, Expression value) - { - return Expression.Invoke(_setValue.Constant(), value); - } - - public bool IsArrayElement - { - get { return false; } - } - - public int[] ElementIndex - { - get { throw new NotSupportedException(); } - } - public MemberInfo UnderlyingMemberInfo { get { throw new NotImplementedException(); } @@ -298,12 +131,12 @@ public MemberInfo UnderlyingMemberInfo public object GetValue(object owner) { - return _getValue(); + return _strongBox.Value; } public void SetValue(object owner, object value) { - _setValue((T) value); + _strongBox.Value = (T) value; } } } diff --git a/src/GraphClimber/ValueDescriptor/IEnumValueDescriptor.cs b/src/GraphClimber/ValueDescriptor/IEnumValueDescriptor.cs index 7f2f6e1..b04b033 100644 --- a/src/GraphClimber/ValueDescriptor/IEnumValueDescriptor.cs +++ b/src/GraphClimber/ValueDescriptor/IEnumValueDescriptor.cs @@ -14,7 +14,7 @@ public interface IEnumValueDescriptor public interface IReadOnlyEnumExactValueDescriptor : IEnumValueDescriptor, IReadOnlyExactValueDescriptor - where TEnum : IConvertible + where TEnum : Enum where TUnderlying : IConvertible { /// @@ -31,7 +31,7 @@ public interface IReadOnlyEnumExactValueDescriptor : public interface IWriteOnlyEnumExactValueDescriptor : IEnumValueDescriptor, IWriteOnlyExactValueDescriptor - where TEnum : IConvertible + where TEnum : Enum where TUnderlying : IConvertible { /// diff --git a/src/GraphClimber/ValueDescriptor/IValueDescriptor.cs b/src/GraphClimber/ValueDescriptor/IValueDescriptor.cs index 1c28c82..ca7d8af 100644 --- a/src/GraphClimber/ValueDescriptor/IValueDescriptor.cs +++ b/src/GraphClimber/ValueDescriptor/IValueDescriptor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace GraphClimber { @@ -12,11 +13,26 @@ public interface IValueDescriptor /// IStateMember StateMember { get; } + /// + /// Gets the children of the current state member. Useful for forward-only readers. + /// + IReadOnlyDictionary Children { get; } + /// /// Gets the owner of the field /// object Owner { get; } + /// + /// Gets a value indicating whether this value is an array element. + /// + bool IsArrayElement { get; } + + /// + /// Gets the index of this value in the array. + /// + int[] ElementIndex { get; } + /// /// Climbs on the (current) value that found in the field by the owner ///