diff --git a/src/NetRx.Store.Monitor.Extension/Properties/AssemblyInfo.cs b/src/NetRx.Store.Monitor.Extension/Properties/AssemblyInfo.cs index 3ee5b06..d39a6a8 100644 --- a/src/NetRx.Store.Monitor.Extension/Properties/AssemblyInfo.cs +++ b/src/NetRx.Store.Monitor.Extension/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ // 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")] +[assembly: AssemblyVersion("2.1.0.0")] +[assembly: AssemblyFileVersion("2.1.0.0")] diff --git a/src/NetRx.Store.Monitor.Extension/app.config b/src/NetRx.Store.Monitor.Extension/app.config index 6da7fbe..ac92545 100644 --- a/src/NetRx.Store.Monitor.Extension/app.config +++ b/src/NetRx.Store.Monitor.Extension/app.config @@ -1,11 +1,11 @@ - + - - + + - + diff --git a/src/NetRx.Store.Monitor.Shared/NetRx.Store.Monitor.Shared.csproj b/src/NetRx.Store.Monitor.Shared/NetRx.Store.Monitor.Shared.csproj index c03bcbd..840cdb6 100644 --- a/src/NetRx.Store.Monitor.Shared/NetRx.Store.Monitor.Shared.csproj +++ b/src/NetRx.Store.Monitor.Shared/NetRx.Store.Monitor.Shared.csproj @@ -6,7 +6,7 @@ Key.snk NetRx.Store.Monitor.Shared - 2.0.0 + 2.1.0 Vitalii Ilchenko Includes library which allows to attach NetRx.Store Monitor tool to an application at a runtime https://github.com/ilchenkob/NetRx.Store diff --git a/src/NetRx.Store.Tests/NetRx.Store.Tests.csproj b/src/NetRx.Store.Tests/NetRx.Store.Tests.csproj index 3d910bd..5b1cff3 100644 --- a/src/NetRx.Store.Tests/NetRx.Store.Tests.csproj +++ b/src/NetRx.Store.Tests/NetRx.Store.Tests.csproj @@ -1,15 +1,19 @@ - netcoreapp2.0 + netcoreapp2.2 - - - - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/NetRx.Store.Tests/State/Actions/TestStateActions.cs b/src/NetRx.Store.Tests/State/Actions/TestStateActions.cs index 0a91cbb..8e566fa 100644 --- a/src/NetRx.Store.Tests/State/Actions/TestStateActions.cs +++ b/src/NetRx.Store.Tests/State/Actions/TestStateActions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; + using NetRx.Store; namespace NetRx.Store.Tests.State.TestStateActions @@ -14,4 +15,12 @@ public SetItemsAction(List payload) : base(payload) { } } + + public class SetReferenceObjectAction : Action + { + public SetReferenceObjectAction(ReferenceObect payload) :base(payload) + { + + } + } } diff --git a/src/NetRx.Store.Tests/State/Reducers/TestStateReducer.cs b/src/NetRx.Store.Tests/State/Reducers/TestStateReducer.cs index 8c0caca..b067b7c 100644 --- a/src/NetRx.Store.Tests/State/Reducers/TestStateReducer.cs +++ b/src/NetRx.Store.Tests/State/Reducers/TestStateReducer.cs @@ -21,6 +21,13 @@ public TestState Reduce(TestState state, TestStateActions.SetItemsAction action) state.Items = action.Payload.ToImmutableList(); return state; } + + public TestState Reduce(TestState state, TestStateActions.SetReferenceObjectAction action) + { + ReduceCalls.Add(action.GetType().FullName); + state.ReferenceObect = action.Payload; + return state; + } } public class SecondaryTestStateReducer : Reducer diff --git a/src/NetRx.Store.Tests/State/States/TestState.cs b/src/NetRx.Store.Tests/State/States/TestState.cs index 93cc2e5..fbd25e1 100644 --- a/src/NetRx.Store.Tests/State/States/TestState.cs +++ b/src/NetRx.Store.Tests/State/States/TestState.cs @@ -25,6 +25,13 @@ public struct SubState }; } + public class ReferenceObect + { + public string Name { get; set; } + + public string Description { get; set; } + } + public struct TestState { public int Id { get; set; } @@ -39,13 +46,17 @@ public struct TestState public ImmutableList Items { get; set; } + public ReferenceObect ReferenceObect { get;set; } + public static TestState Initial => new TestState { Id = 1, Name = "empty_name", Amount = 0.7m, IsEnabled = true, - SubState = SubState.Initial + SubState = SubState.Initial, + ReferenceObect = new ReferenceObect() + }; } diff --git a/src/NetRx.Store.Tests/Store/StoreTest.cs b/src/NetRx.Store.Tests/Store/StoreTest.cs index 22afc53..d64d4ae 100644 --- a/src/NetRx.Store.Tests/Store/StoreTest.cs +++ b/src/NetRx.Store.Tests/Store/StoreTest.cs @@ -4,8 +4,11 @@ using NetRx.Store.Tests.State.Effects; using NetRx.Store.Tests.State.Reducers; using NetRx.Store.Tests.State.TestStateActions; + +using System; using System.Collections.Generic; using System.Linq; + using Xunit; namespace NetRx.Store.Tests @@ -24,18 +27,6 @@ public void WithState_Should_Throw_InvalidStateTypeException_When_Reference_stat Assert.Contains(nameof(InvalidTypeState), exception.Message); } - [Fact] - public void WithState_Should_Throw_InvalidStatePropertyTypeException_When_Reference_property_type_passed() - { - var exception = Record.Exception( - () => Store.Create().WithState(new InvalidPropertyTypeState(), new InvalidPropertyTypeStateReducer()) - ); - - Assert.NotNull(exception); - Assert.IsType(exception); - Assert.Contains(nameof(InvalidPropertyTypeState.Model), exception.Message); - } - [Fact] public void WithState_Should_Throw_InvalidStatePropertyTypeException_When_not_Immutable_collection_passed() { @@ -155,5 +146,26 @@ public void Dispatch_Should_call_Reducer_Reduce_and_Effect_Invoke_method_When_ca Assert.Single(reducer.ReduceCalls.Where(c => c == typeof(SetItemsAction).FullName)); Assert.Equal(1, effect.CallCount); } + + [Fact] + public void Dispatch_Should_call_Reducer_Reduce_and_observable_should_invoke() + { + var reducer = new TestStateReducer(); + var store = Store.Create() + .WithState(TestState.Initial, reducer); + + var newObject = new ReferenceObect(); + ReferenceObect selectedObect = null; + + var disposable = store.Select(f=> f.ReferenceObect) + .Subscribe(f => selectedObect = f); + + store.Dispatch(new SetReferenceObjectAction(newObject)); + + disposable.Dispose(); + + Assert.Same(newObject, selectedObect); + + } } } diff --git a/src/NetRx.Store/NetRx.Store.csproj b/src/NetRx.Store/NetRx.Store.csproj index 70002c8..4047083 100644 --- a/src/NetRx.Store/NetRx.Store.csproj +++ b/src/NetRx.Store/NetRx.Store.csproj @@ -4,7 +4,7 @@ netstandard2.0 NetRx NetRx.Store - 2.0.0 + 2.1.0 Vitalii Ilchenko State management for .Net projects, inspired by @ngrx/store https://github.com/ilchenkob/NetRx.Store @@ -17,13 +17,14 @@ MIT + 2.1.0.0 - - - - + + + + diff --git a/src/NetRx.Store/Store/StateWrapper.cs b/src/NetRx.Store/Store/StateWrapper.cs index 6517252..8119a5b 100644 --- a/src/NetRx.Store/Store/StateWrapper.cs +++ b/src/NetRx.Store/Store/StateWrapper.cs @@ -10,6 +10,7 @@ namespace NetRx.Store internal sealed class StateWrapper { internal const string EnumerableFieldMarker = "#"; + internal const string ReferenceFieldMarker = "*"; private static readonly Dictionary>> _gettersCache = new Dictionary>>(); @@ -51,6 +52,8 @@ private void BuildGetters(Type type, string prefix) { var isString = p.PropertyType == stringType; var isEnumerable = p.PropertyType.GetInterface(typeof(IEnumerable<>).FullName) != null && !isString; + var isReferenceType = p.PropertyType.IsClass && !isString || (p.PropertyType.IsInterface && p.PropertyType.GetInterface(typeof(IEnumerable<>).FullName) == null); + if (isEnumerable) { var hasImmutableInterface = p.PropertyType @@ -65,10 +68,12 @@ private void BuildGetters(Type type, string prefix) throw new InvalidStatePropertyTypeException( $"'{p.Name}' cannot have reference type '{nonValueType.FullName}'. Should have 'struct' type"); } - else if (!p.PropertyType.IsValueType && + else if (!isReferenceType && + !p.PropertyType.IsValueType && !isString && !isEnumerable) { + throw new InvalidStatePropertyTypeException($"'{p.Name}' property of {prefix} cannot have reference type. Should have 'struct' type"); } @@ -80,21 +85,24 @@ private void BuildGetters(Type type, string prefix) wrappedObjectParameter ); - string name = isEnumerable ? $"{prefix}.{p.Name}{EnumerableFieldMarker}" : $"{prefix}.{p.Name}"; + string name = isEnumerable + ? $"{prefix}.{p.Name}{EnumerableFieldMarker}" + : isReferenceType + ? $"{prefix}.{p.Name}{ReferenceFieldMarker}" + : $"{prefix}.{p.Name}"; _gettersCache[OriginalTypeName].Add(name, getExpression.Compile()); - if (!p.PropertyType.FullName.StartsWith("System.", StringComparison.InvariantCulture) - && !isEnumerable) - { - BuildGetters(p.PropertyType, name); - } } } public object Get(string name) { - var key = _gettersCache[OriginalTypeName].ContainsKey(name) ? name : $"{name}{EnumerableFieldMarker}"; + var key = _gettersCache[OriginalTypeName].ContainsKey(name) + ? name + : _gettersCache[OriginalTypeName].ContainsKey($"{name}{EnumerableFieldMarker}") + ? $"{name}{EnumerableFieldMarker}" + : $"{name}{ReferenceFieldMarker}"; var propNamePart = key.Substring(OriginalTypeName.Length); var pointIndex = propNamePart.LastIndexOf('.'); @@ -124,6 +132,7 @@ public object Get(string name) public bool HasGeter(string name) => _gettersCache[OriginalTypeName].ContainsKey(name) || _gettersCache[OriginalTypeName].ContainsKey($"{name}{EnumerableFieldMarker}") || + _gettersCache[OriginalTypeName].ContainsKey($"{name}{ReferenceFieldMarker}") || string.Equals(name, OriginalTypeName); public object Original { get; private set; } diff --git a/src/NetRx.Store/Store/Store.cs b/src/NetRx.Store/Store/Store.cs index bf494a9..13ccda9 100644 --- a/src/NetRx.Store/Store/Store.cs +++ b/src/NetRx.Store/Store/Store.cs @@ -184,10 +184,14 @@ private void DetectChanges(List<(string, StateWrapper)> modifiedStates) var hasChanges = field.EndsWith(StateWrapper.EnumerableFieldMarker, StringComparison.InvariantCulture) ? !Equals(newValue?.GetHashCode(), prevValue?.GetHashCode()) - : !Equals(newValue, prevValue); + : field.EndsWith(StateWrapper.ReferenceFieldMarker, StringComparison.InvariantCulture) + ? !ReferenceEquals(newValue,prevValue) + : !Equals(newValue, prevValue); if (hasChanges) { - NotifySubscribers(currState, field.Replace(StateWrapper.EnumerableFieldMarker, string.Empty)); + NotifySubscribers(currState, + field.Replace(StateWrapper.EnumerableFieldMarker, string.Empty) + .Replace(StateWrapper.ReferenceFieldMarker, string.Empty)); } } }