Browse Source

Allow to ignore some properties on mapping extensible objects.

pull/3488/head
Halil İbrahim Kalkan 6 years ago
parent
commit
d506d40608
  1. 8
      framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs
  2. 237
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtendedObjectMapper.cs
  3. 199
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs
  4. 6
      framework/test/Volo.Abp.AutoMapper.Tests/AutoMapper/AbpAutoMapperExtensibleDtoExtensions_Tests.cs
  5. 8
      framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/ObjectMapperExtensions_Tests.cs
  6. 2
      framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyMapProfile.cs
  7. 4
      framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs
  8. 27
      framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs

8
framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs

@ -8,7 +8,8 @@ namespace AutoMapper
{
public static IMappingExpression<TSource, TDestination> MapExtraProperties<TSource, TDestination>(
this IMappingExpression<TSource, TDestination> mappingExpression,
MappingPropertyDefinitionChecks? definitionChecks = null)
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
where TDestination : IHasExtraProperties
where TSource : IHasExtraProperties
{
@ -22,11 +23,12 @@ namespace AutoMapper
? new Dictionary<string, object>()
: new Dictionary<string, object>(extraProps);
HasExtraPropertiesObjectExtendingExtensions
ExtensibleObjectMapper
.MapExtraPropertiesTo<TSource, TDestination>(
source.ExtraProperties,
result,
definitionChecks
definitionChecks,
ignoredProperties
);
return result;

237
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtendedObjectMapper.cs

@ -0,0 +1,237 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Data;
namespace Volo.Abp.ObjectExtending
{
public static class ExtensibleObjectMapper
{
/// <summary>
/// Copies extra properties from the <paramref name="source"/> object
/// to the <paramref name="destination"/> object.
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
/// <typeparam name="TSource">Source class type</typeparam>
/// <typeparam name="TDestination">Destination class type</typeparam>
/// <param name="source">The source object</param>
/// <param name="destination">The destination object</param>
/// <param name="definitionChecks">
/// Controls which properties to map.
/// </param>
/// <param name="ignoredProperties">Used to ignore some properties</param>
public static void MapExtraPropertiesTo<TSource, TDestination>(
[NotNull] TSource source,
[NotNull] TDestination destination,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
where TSource : IHasExtraProperties
where TDestination : IHasExtraProperties
{
Check.NotNull(source, nameof(source));
Check.NotNull(destination, nameof(destination));
ExtensibleObjectMapper.MapExtraPropertiesTo(
typeof(TSource),
typeof(TDestination),
source.ExtraProperties,
destination.ExtraProperties,
definitionChecks,
ignoredProperties
);
}
/// <summary>
/// Copies extra properties from the <paramref name="sourceDictionary"/> object
/// to the <paramref name="destinationDictionary"/> object.
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
/// <typeparam name="TSource">Source class type (for definition check)</typeparam>
/// <typeparam name="TDestination">Destination class type (for definition check)</typeparam>
/// <param name="sourceDictionary">The source dictionary object</param>
/// <param name="destinationDictionary">The destination dictionary object</param>
/// <param name="definitionChecks">
/// Controls which properties to map.
/// </param>
/// <param name="ignoredProperties">Used to ignore some properties</param>
public static void MapExtraPropertiesTo<TSource, TDestination>(
[NotNull] Dictionary<string, object> sourceDictionary,
[NotNull] Dictionary<string, object> destinationDictionary,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
where TSource : IHasExtraProperties
where TDestination : IHasExtraProperties
{
MapExtraPropertiesTo(
typeof(TSource),
typeof(TDestination),
sourceDictionary,
destinationDictionary,
definitionChecks,
ignoredProperties
);
}
/// <summary>
/// Copies extra properties from the <paramref name="sourceDictionary"/> object
/// to the <paramref name="destinationDictionary"/> object.
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
/// <param name="sourceType">Source type (for definition check)</param>
/// <param name="destinationType">Destination class type (for definition check)</param>
/// <param name="sourceDictionary">The source dictionary object</param>
/// <param name="destinationDictionary">The destination dictionary object</param>
/// <param name="definitionChecks">
/// Controls which properties to map.
/// </param>
/// <param name="ignoredProperties">Used to ignore some properties</param>
public static void MapExtraPropertiesTo(
[NotNull] Type sourceType,
[NotNull] Type destinationType,
[NotNull] Dictionary<string, object> sourceDictionary,
[NotNull] Dictionary<string, object> destinationDictionary,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
{
Check.AssignableTo<IHasExtraProperties>(sourceType, nameof(sourceType));
Check.AssignableTo<IHasExtraProperties>(destinationType, nameof(destinationType));
Check.NotNull(sourceDictionary, nameof(sourceDictionary));
Check.NotNull(destinationDictionary, nameof(destinationDictionary));
var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType);
var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType);
foreach (var keyValue in sourceDictionary)
{
if (CanMapProperty(
keyValue.Key,
sourceObjectExtension,
destinationObjectExtension,
definitionChecks,
ignoredProperties))
{
destinationDictionary[keyValue.Key] = keyValue.Value;
}
}
}
//TODO: Move these methods to a class like ObjectExtensionHelper
public static bool CanMapProperty<TSource, TDestination>(
[NotNull] string propertyName,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
{
return CanMapProperty(
typeof(TSource),
typeof(TDestination),
propertyName,
definitionChecks,
ignoredProperties
);
}
public static bool CanMapProperty(
[NotNull] Type sourceType,
[NotNull] Type destinationType,
[NotNull] string propertyName,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
{
Check.AssignableTo<IHasExtraProperties>(sourceType, nameof(sourceType));
Check.AssignableTo<IHasExtraProperties>(destinationType, nameof(destinationType));
Check.NotNull(propertyName, nameof(propertyName));
var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType);
var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType);
return CanMapProperty(
propertyName,
sourceObjectExtension,
destinationObjectExtension,
definitionChecks,
ignoredProperties);
}
private static bool CanMapProperty(
[NotNull] string propertyName,
[CanBeNull] ObjectExtensionInfo sourceObjectExtension,
[CanBeNull] ObjectExtensionInfo destinationObjectExtension,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
{
Check.NotNull(propertyName, nameof(propertyName));
if (ignoredProperties != null &&
ignoredProperties.Contains(propertyName))
{
return false;
}
if (definitionChecks != null)
{
if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Source))
{
if (sourceObjectExtension == null)
{
return false;
}
if (!sourceObjectExtension.HasProperty(propertyName))
{
return false;
}
}
if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Destination))
{
if (destinationObjectExtension == null)
{
return false;
}
if (!destinationObjectExtension.HasProperty(propertyName))
{
return false;
}
}
return true;
}
else
{
var sourcePropertyDefinition = sourceObjectExtension?.GetPropertyOrNull(propertyName);
var destinationPropertyDefinition = destinationObjectExtension?.GetPropertyOrNull(propertyName);
if (sourcePropertyDefinition != null)
{
if (destinationPropertyDefinition != null)
{
return true;
}
if (sourcePropertyDefinition.CheckPairDefinitionOnMapping == false)
{
return true;
}
}
else if (destinationPropertyDefinition != null)
{
if (destinationPropertyDefinition.CheckPairDefinitionOnMapping == false)
{
return true;
}
}
return false;
}
}
}
}

199
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using JetBrains.Annotations;
using Volo.Abp.Data;
namespace Volo.Abp.ObjectExtending
@ -10,7 +8,7 @@ namespace Volo.Abp.ObjectExtending
/// <summary>
/// Copies extra properties from the <paramref name="source"/> object
/// to the <paramref name="destination"/> object.
///
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
@ -19,198 +17,23 @@ namespace Volo.Abp.ObjectExtending
/// <param name="source">The source object</param>
/// <param name="destination">The destination object</param>
/// <param name="definitionChecks">
/// Controls which properties to map.
/// Controls which properties to map.
/// </param>
/// <param name="ignoredProperties">Used to ignore some properties</param>
public static void MapExtraPropertiesTo<TSource, TDestination>(
[NotNull] this TSource source,
[NotNull] TDestination destination,
MappingPropertyDefinitionChecks? definitionChecks = null)
where TSource : IHasExtraProperties
where TDestination : IHasExtraProperties
{
Check.NotNull(source, nameof(source));
Check.NotNull(destination, nameof(destination));
MapExtraPropertiesTo(
typeof(TSource),
typeof(TDestination),
source.ExtraProperties,
destination.ExtraProperties,
definitionChecks
);
}
/// <summary>
/// Copies extra properties from the <paramref name="sourceDictionary"/> object
/// to the <paramref name="destinationDictionary"/> object.
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
/// <typeparam name="TSource">Source class type (for definition check)</typeparam>
/// <typeparam name="TDestination">Destination class type (for definition check)</typeparam>
/// <param name="sourceDictionary">The source dictionary object</param>
/// <param name="destinationDictionary">The destination dictionary object</param>
/// <param name="definitionChecks">
/// Controls which properties to map.
/// </param>
public static void MapExtraPropertiesTo<TSource, TDestination>(
[NotNull] Dictionary<string, object> sourceDictionary,
[NotNull] Dictionary<string, object> destinationDictionary,
MappingPropertyDefinitionChecks? definitionChecks = null)
MappingPropertyDefinitionChecks? definitionChecks = null,
string[] ignoredProperties = null)
where TSource : IHasExtraProperties
where TDestination : IHasExtraProperties
{
MapExtraPropertiesTo(
typeof(TSource),
typeof(TDestination),
sourceDictionary,
destinationDictionary,
definitionChecks
ExtensibleObjectMapper.MapExtraPropertiesTo(
source,
destination,
definitionChecks,
ignoredProperties
);
}
/// <summary>
/// Copies extra properties from the <paramref name="sourceDictionary"/> object
/// to the <paramref name="destinationDictionary"/> object.
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
/// <param name="sourceType">Source type (for definition check)</param>
/// <param name="destinationType">Destination class type (for definition check)</param>
/// <param name="sourceDictionary">The source dictionary object</param>
/// <param name="destinationDictionary">The destination dictionary object</param>
/// <param name="definitionChecks">
/// Controls which properties to map.
/// </param>
public static void MapExtraPropertiesTo(
[NotNull] Type sourceType,
[NotNull] Type destinationType,
[NotNull] Dictionary<string, object> sourceDictionary,
[NotNull] Dictionary<string, object> destinationDictionary,
MappingPropertyDefinitionChecks? definitionChecks = null)
{
Check.AssignableTo<IHasExtraProperties>(sourceType, nameof(sourceType));
Check.AssignableTo<IHasExtraProperties>(destinationType, nameof(destinationType));
Check.NotNull(sourceDictionary, nameof(sourceDictionary));
Check.NotNull(destinationDictionary, nameof(destinationDictionary));
var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType);
var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType);
foreach (var keyValue in sourceDictionary)
{
if (CanMapProperty(
keyValue.Key,
sourceObjectExtension,
destinationObjectExtension,
definitionChecks))
{
destinationDictionary[keyValue.Key] = keyValue.Value;
}
}
}
//TODO: Move these methods to a class like ObjectExtensionHelper
public static bool CanMapProperty<TSource, TDestination>(
[NotNull] string propertyName,
MappingPropertyDefinitionChecks? definitionChecks = null)
{
return CanMapProperty(
typeof(TSource),
typeof(TDestination),
propertyName,
definitionChecks
);
}
public static bool CanMapProperty(
[NotNull] Type sourceType,
[NotNull] Type destinationType,
[NotNull] string propertyName,
MappingPropertyDefinitionChecks? definitionChecks = null)
{
Check.AssignableTo<IHasExtraProperties>(sourceType, nameof(sourceType));
Check.AssignableTo<IHasExtraProperties>(destinationType, nameof(destinationType));
Check.NotNull(propertyName, nameof(propertyName));
var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType);
var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType);
return CanMapProperty(
propertyName,
sourceObjectExtension,
destinationObjectExtension,
definitionChecks);
}
private static bool CanMapProperty(
[NotNull] string propertyName,
[CanBeNull] ObjectExtensionInfo sourceObjectExtension,
[CanBeNull] ObjectExtensionInfo destinationObjectExtension,
MappingPropertyDefinitionChecks? definitionChecks = null)
{
Check.NotNull(propertyName, nameof(propertyName));
if (definitionChecks != null)
{
if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Source))
{
if (sourceObjectExtension == null)
{
return false;
}
if (!sourceObjectExtension.HasProperty(propertyName))
{
return false;
}
}
if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Destination))
{
if (destinationObjectExtension == null)
{
return false;
}
if (!destinationObjectExtension.HasProperty(propertyName))
{
return false;
}
}
return true;
}
else
{
var sourcePropertyDefinition = sourceObjectExtension?.GetPropertyOrNull(propertyName);
var destinationPropertyDefinition = destinationObjectExtension?.GetPropertyOrNull(propertyName);
if (sourcePropertyDefinition != null)
{
if (destinationPropertyDefinition != null)
{
return true;
}
if (sourcePropertyDefinition.CheckPairDefinitionOnMapping == false)
{
return true;
}
}
else if (destinationPropertyDefinition != null)
{
if (destinationPropertyDefinition.CheckPairDefinitionOnMapping == false)
{
return true;
}
}
return false;
}
}
}
}

6
framework/test/Volo.Abp.AutoMapper.Tests/AutoMapper/AbpAutoMapperExtensibleDtoExtensions_Tests.cs

@ -24,7 +24,8 @@ namespace AutoMapper
.SetProperty("Name", "John")
.SetProperty("Age", 42)
.SetProperty("ChildCount", 2)
.SetProperty("Sex", "male");
.SetProperty("Sex", "male")
.SetProperty("CityName", "Adana");
var personDto = new ExtensibleTestPersonDto()
.SetProperty("ExistingDtoProperty", "existing-value");
@ -32,10 +33,11 @@ namespace AutoMapper
_objectMapper.Map(person, personDto);
personDto.GetProperty<string>("Name").ShouldBe("John"); //Defined in both classes
personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination
personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source
personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes
personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
personDto.HasProperty("CityName").ShouldBeFalse(); //Ignored
}
}
}

8
framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/ObjectMapperExtensions_Tests.cs

@ -20,7 +20,13 @@ namespace Volo.Abp.AutoMapper
[Fact]
public void Should_Map_Objects_With_AutoMap_Attributes()
{
var dto = _objectMapper.Map(typeof(MyEntity), typeof(MyEntityDto), new MyEntity { Number = 42 });
var dto = _objectMapper.Map<MyEntity, MyEntityDto>(
new MyEntity
{
Number = 42
}
);
dto.As<MyEntityDto>().Number.ShouldBe(42);
}
}

2
framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyMapProfile.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.AutoMapper.SampleClasses
CreateMap<MyEntity, MyEntityDto>().ReverseMap();
CreateMap<ExtensibleTestPerson, ExtensibleTestPersonDto>()
.MapExtraProperties();
.MapExtraProperties(ignoredProperties: new[] { "CityName" });
}
}
}

4
framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs

@ -20,8 +20,10 @@ namespace Volo.Abp.ObjectExtending
.AddOrUpdateProperty<ExtensibleTestPerson, string>("Name")
.AddOrUpdateProperty<ExtensibleTestPerson, int>("Age")
.AddOrUpdateProperty<ExtensibleTestPerson, string>("NoPairCheck", options => options.CheckPairDefinitionOnMapping = false)
.AddOrUpdateProperty<ExtensibleTestPerson, string>("CityName")
.AddOrUpdateProperty<ExtensibleTestPersonDto, string>("Name")
.AddOrUpdateProperty<ExtensibleTestPersonDto, int>("ChildCount");
.AddOrUpdateProperty<ExtensibleTestPersonDto, int>("ChildCount")
.AddOrUpdateProperty<ExtensibleTestPersonDto, int>("CityName");
});
}
}

27
framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs

@ -17,23 +17,39 @@ namespace Volo.Abp.ObjectExtending
.SetProperty("Age", 42)
.SetProperty("ChildCount", 2)
.SetProperty("Sex", "male")
.SetProperty("NoPairCheck", "test-value");
.SetProperty("NoPairCheck", "test-value")
.SetProperty("CityName", "Adana");
_personDto = new ExtensibleTestPersonDto()
.SetProperty("ExistingDtoProperty", "existing-value");
}
[Fact]
public void MapExtraPropertiesTo_Should_Only_Map_Defined_Properties_By_Default()
{
_person.MapExtraPropertiesTo(_personDto);
_personDto.GetProperty<string>("Name").ShouldBe("John"); //Defined in both classes
_personDto.GetProperty<string>("CityName").ShouldBe("Adana"); //Defined in both classes
_personDto.GetProperty<string>("NoPairCheck").ShouldBe("test-value"); //CheckPairDefinitionOnMapping = false
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
_personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination
_personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source
_personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes
}
[Fact]
public void MapExtraPropertiesTo_Should_Ignore_Desired_Properties()
{
_person.MapExtraPropertiesTo(_personDto, ignoredProperties: new[] { "CityName" });
_personDto.GetProperty<string>("Name").ShouldBe("John"); //Defined in both classes
_personDto.GetProperty<string>("NoPairCheck").ShouldBe("test-value"); //CheckPairDefinitionOnMapping = false
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
_personDto.HasProperty("CityName").ShouldBeFalse(); //Ignored!
_personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination
_personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source
_personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes
}
[Fact]
@ -42,10 +58,11 @@ namespace Volo.Abp.ObjectExtending
_person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionChecks.Source);
_personDto.GetProperty<string>("Name").ShouldBe("John"); //Defined in both classes
_personDto.GetProperty<string>("CityName").ShouldBe("Adana"); //Defined in both classes
_personDto.GetProperty<int>("Age").ShouldBe(42); //Defined in source
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
_personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source
_personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
}
[Fact]
@ -54,10 +71,11 @@ namespace Volo.Abp.ObjectExtending
_person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionChecks.Destination);
_personDto.GetProperty<string>("Name").ShouldBe("John"); //Defined in both classes
_personDto.GetProperty<string>("CityName").ShouldBe("Adana"); //Defined in both classes
_personDto.GetProperty<int>("ChildCount").ShouldBe(2); //Defined in destination
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
_personDto.HasProperty("Age").ShouldBeFalse(); //Not defined in destination
_personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
}
[Fact]
@ -66,6 +84,7 @@ namespace Volo.Abp.ObjectExtending
_person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionChecks.None);
_personDto.GetProperty<string>("Name").ShouldBe("John");
_personDto.GetProperty<string>("CityName").ShouldBe("Adana");
_personDto.GetProperty<int>("Age").ShouldBe(42);
_personDto.GetProperty<int>("ChildCount").ShouldBe(2);
_personDto.GetProperty<string>("Sex").ShouldBe("male");

Loading…
Cancel
Save