diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs b/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs index 599acdb8e..5e085791d 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs @@ -1,6 +1,7 @@ -using System.Reflection; using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ExtensionModel.Types; +using System.Reflection; namespace ExtendedXmlSerializer.ContentModel.Members { @@ -23,8 +24,7 @@ public InstanceMemberSerialization(ISpecification specification, IMemb public IMemberSerialization Get(object parameter) { - var type = parameter.GetType() - .GetTypeInfo(); + var type = parameter is ITypeAware aware ? aware.Get() : parameter.GetType().GetTypeInfo(); var result = _specification.IsSatisfiedBy(type) ? _serializations.Get(type) : _serialization; return result; } diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/MemberContext.cs b/src/ExtendedXmlSerializer/ContentModel/Members/MemberContext.cs new file mode 100644 index 000000000..ed32e0824 --- /dev/null +++ b/src/ExtendedXmlSerializer/ContentModel/Members/MemberContext.cs @@ -0,0 +1,18 @@ +using System.Collections.Immutable; +using System.Reflection; + +namespace ExtendedXmlSerializer.ContentModel.Members +{ + readonly struct MemberContext + { + public MemberContext(TypeInfo reflectedType, ImmutableArray members) + { + ReflectedType = reflectedType; + Members = members; + } + + public TypeInfo ReflectedType { get; } + + public ImmutableArray Members { get; } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs b/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs index 48fe66962..038259237 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs @@ -19,11 +19,11 @@ public MemberInnerContentHandler(IInstanceMemberSerialization serialization, IMe public bool IsSatisfiedBy(IInnerContent parameter) { - var content = parameter.Get(); - var key = _formatter.Get(content); - var member = _serialization.Get(parameter.Current) - .Get(key); - var result = member != null; + var content = parameter.Get(); + var key = _formatter.Get(content); + var memberSerialization = _serialization.Get(parameter.Current); + var member = memberSerialization.Get(key); + var result = member != null; if (result) { _handler.Handle(parameter, member); diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs index f17775cfb..5ba133aa3 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs @@ -45,7 +45,8 @@ public IActivator Get(Type parameter) ActivationContextActivator Activator(ConstructorInfo constructor, ImmutableArray members) { var activator = new Source(constructor).ToSelectionDelegate(); - var contexts = new ActivationContexts(_accessors, members, activator); + var context = new MemberContext(constructor.ReflectedType.GetTypeInfo(), members); + var contexts = new ActivationContexts(_accessors, context, activator); var defaults = constructor.GetParameters() .Where(x => x.IsOptional) .Select(x => Pairs.Create(x.Name, x.DefaultValue)) diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs index 56e71d72d..553967bde 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs @@ -41,7 +41,8 @@ public IActivator Get(Type parameter) ActivationContextActivator Activator(ConstructorInfo constructor, ImmutableArray members) { var activator = new Source(constructor).ToSelectionDelegate(); - var contexts = new ActivationContexts(_accessors, members, activator); + var context = new MemberContext(constructor.ReflectedType.GetTypeInfo(), members); + var contexts = new ActivationContexts(_accessors, context, activator); var defaults = constructor.GetParameters() .Where(x => x.IsOptional) .Select(x => Pairs.Create(x.Name, x.DefaultValue)) diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs b/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs index bc86ba92e..31c0f494b 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs @@ -5,15 +5,16 @@ using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Parsing; using ExtendedXmlSerializer.Core.Sources; -using Sprache; using ExtendedXmlSerializer.ExtensionModel.Expressions; using ExtendedXmlSerializer.ExtensionModel.Types; using ExtendedXmlSerializer.ReflectionModel; +using Sprache; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; + // ReSharper disable TooManyDependencies namespace ExtendedXmlSerializer.ExtensionModel.Markup @@ -79,7 +80,8 @@ protected override object Create(MarkupExtensionParts parameter) .Zip(candidates, (info, evaluation) => evaluation.Get(info)) .ToArray(); var activator = new ConstructedActivator(constructor, arguments); - var extension = new ActivationContexts(_accessors, members, activator).Get(dictionary) + var context = new MemberContext(constructor.ReflectedType.GetTypeInfo(), members); + var extension = new ActivationContexts(_accessors, context, activator).Get(dictionary) .Get() .AsValid(); var result = extension.ProvideValue(new Provider(_provider, _services.Appending(parameter) diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContext.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContext.cs index 21cb8fa97..a1440cb06 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContext.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContext.cs @@ -1,17 +1,22 @@ +using ExtendedXmlSerializer.Core.Sources; using System; using System.Collections; -using ExtendedXmlSerializer.Core.Sources; +using System.Reflection; namespace ExtendedXmlSerializer.ExtensionModel.Types { - sealed class ActivationContext : IActivationContext + sealed class ActivationContext : IActivationContext, ITypeAware { + readonly TypeInfo _subject; readonly ITableSource _source; readonly Func _activator; readonly IList _list; - public ActivationContext(ITableSource source, Func activator, IList list) + // ReSharper disable once TooManyDependencies + public ActivationContext(TypeInfo subject, ITableSource source, Func activator, + IList list) { + _subject = subject; _source = source; _activator = activator; _list = list; @@ -60,5 +65,7 @@ public object this[int index] get => _list[index]; set => _list[index] = value; } + + TypeInfo ISource.Get() => _subject; } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs index c38f8a355..522998604 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs @@ -5,7 +5,6 @@ using ExtendedXmlSerializer.ReflectionModel; using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; namespace ExtendedXmlSerializer.ExtensionModel.Types @@ -13,22 +12,23 @@ namespace ExtendedXmlSerializer.ExtensionModel.Types sealed class ActivationContexts : IActivationContexts { readonly IMemberAccessors _accessors; - readonly ImmutableArray _members; + readonly MemberContext _members; readonly ITableSource _table; readonly Func, IActivator> _activator; - public ActivationContexts(IMemberAccessors accessors, ImmutableArray members, IActivator activator) + public ActivationContexts(IMemberAccessors accessors, MemberContext members, IActivator activator) : this(accessors, members, activator.Accept) {} - public ActivationContexts(IMemberAccessors accessors, ImmutableArray members, + public ActivationContexts(IMemberAccessors accessors, MemberContext members, Func, IActivator> activator) : this(accessors, members, - new TableSource(members.ToDictionary(x => x.Name, + new TableSource(members.Members + .ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase)), activator) {} // ReSharper disable once TooManyDependencies - public ActivationContexts(IMemberAccessors accessors, ImmutableArray members, + public ActivationContexts(IMemberAccessors accessors, MemberContext members, ITableSource table, Func, IActivator> activator) { @@ -42,12 +42,12 @@ public IActivationContext Get(IDictionary parameter) { var source = new TableSource(parameter); var list = new List(); - var command = new CompositeCommand(new ApplyMemberValuesCommand(_accessors, _members, source), + var command = new CompositeCommand(new ApplyMemberValuesCommand(_accessors, _members.Members, + source), new AddItemsCommand(list)); var alteration = new ConfiguringAlteration(command); var activator = new AlteringActivator(alteration, _activator(new Store(source, _table).Get)); - var result = new ActivationContext(source, activator.Singleton() - .Get, list); + var result = new ActivationContext(_members.ReflectedType, source, activator.Singleton().Get, list); return result; } diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationContext.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationContext.cs index a73076198..8e48bc57d 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationContext.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationContext.cs @@ -1,6 +1,6 @@ -using System.Collections; using ExtendedXmlSerializer.Core.Sources; using ExtendedXmlSerializer.ReflectionModel; +using System.Collections; namespace ExtendedXmlSerializer.ExtensionModel.Types { diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ITypeAware.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ITypeAware.cs new file mode 100644 index 000000000..1c7937d2a --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ITypeAware.cs @@ -0,0 +1,7 @@ +using ExtendedXmlSerializer.Core.Sources; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + interface ITypeAware : ISource {} +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ReflectionModel/ApplyMemberValuesCommand.cs b/src/ExtendedXmlSerializer/ReflectionModel/ApplyMemberValuesCommand.cs index 028e4bed7..153ce0ce1 100644 --- a/src/ExtendedXmlSerializer/ReflectionModel/ApplyMemberValuesCommand.cs +++ b/src/ExtendedXmlSerializer/ReflectionModel/ApplyMemberValuesCommand.cs @@ -1,7 +1,7 @@ -using System.Collections.Immutable; using ExtendedXmlSerializer.ContentModel.Members; using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Sources; +using System.Collections.Immutable; namespace ExtendedXmlSerializer.ReflectionModel { @@ -23,8 +23,7 @@ public void Execute(object parameter) { foreach (var member in _members) { - var isSatisfiedBy = _values.IsSatisfiedBy(member.Name); - if (isSatisfiedBy) + if (_values.IsSatisfiedBy(member.Name)) { var access = _accessors.Get(member); var value = _values.Get(member.Name); diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue427Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue427Tests.cs new file mode 100644 index 000000000..cc318920b --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue427Tests.cs @@ -0,0 +1,108 @@ +using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.Tests.ReportedIssues.Support; +using FluentAssertions; +using System.Linq; +using Xunit; +// ReSharper disable UnusedAutoPropertyAccessor.Local + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ + public sealed class Issue427Tests + { + [Fact] + public void Verify() + { + var instance = new Subject("Hello World", 123); + var serializer = new ConfigurationContainer().EnableParameterizedContent().Create().ForTesting(); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + + var element = new Base[] {instance}; + serializer.Cycle(element).Should().BeEquivalentTo(element.Cast()); + + } + + [Fact] + public void VerifyBasic() + { + var instance = new BasicSubject{Name = "Hello World", Number = 123}; + var serializer = new ConfigurationContainer().Create().ForTesting(); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + + var element = new Basic[] {instance}; + serializer.Cycle(element).Should().BeEquivalentTo(element.Cast()); + + } + + [Fact] + public void VerifyReported() + { + var config = new NewFieldInfo(FieldType.Int) + { + Name = "abc", + TargetName = "edf" + }; + + var serializer = new ConfigurationContainer().EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + + var instance = new NewTypeInfo[] {config}; + serializer.Cycle(instance).Should().BeEquivalentTo(instance.Cast()); + } + + class BasicSubject : Basic + { + public string Name { get; set; } + } + + class Basic + { + public int Number { get; set; } + } + + class Subject : Base + { + public Subject(string name, int number) : base(number) => Name = name; + + public string Name { get; } + } + + class Base + { + public Base(int number) => Number = number; + + public int Number { get; } + } + + public enum FieldType + { + Int, + Bool + } + + public class NewFieldInfo : NewTypeInfo + { + public NewFieldInfo(FieldType type) : base(type) {} + + public string Description { get; set; } = null; + + public bool IsRequired { get; set; } + + public string TargetName { get; set; } + } + + public class NewTypeInfo + { + public NewTypeInfo(FieldType type) + { + Type = type; + } + + public FieldType Type { get; } + + public string Name { get; set; } + } + } +} \ No newline at end of file