-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added
EnableImplicitTypingByInspecting<T>
extension method (#495)
- Loading branch information
Showing
3 changed files
with
223 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
src/ExtendedXmlSerializer/ExtensionModel/Types/Sources/InspectedPropertyTypes.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Xml.Serialization; | ||
using ExtendedXmlSerializer.Core.Sources; | ||
|
||
namespace ExtendedXmlSerializer.ExtensionModel.Types.Sources | ||
{ | ||
/// <summary> | ||
/// Iterates through all public properties in given type and resolve its types. Then recursively iterates through them. | ||
/// </summary> | ||
/// <typeparam name="T">The type to query.</typeparam> | ||
public sealed class InspectedPropertyTypes<T> : Items<Type> | ||
{ | ||
/// <summary> | ||
/// Creates a new instance. | ||
/// </summary> | ||
public InspectedPropertyTypes() : base(new InspectedPropertyTypes(typeof(T))) | ||
{ | ||
|
||
} | ||
} | ||
|
||
/// <summary> | ||
/// Iterates through all public properties in given type and resolve its types. Then recursively iterates through them. | ||
/// </summary> | ||
public sealed class InspectedPropertyTypes : Items<Type> | ||
{ | ||
readonly static HashSet<Type> IgnoredTypes = new HashSet<Type> | ||
{ | ||
typeof(string), | ||
typeof(int), | ||
typeof(uint), | ||
typeof(long), | ||
typeof(ulong), | ||
typeof(short), | ||
typeof(ushort), | ||
typeof(double), | ||
typeof(bool), | ||
typeof(decimal), | ||
typeof(byte), | ||
typeof(sbyte), | ||
typeof(DateTime) | ||
}; | ||
|
||
/// <summary> | ||
/// Creates a new instance. | ||
/// </summary> | ||
/// <param name="type">The reference type to query.</param> | ||
public InspectedPropertyTypes(Type type) : base(GetPropertyTypes(type)) | ||
{ | ||
|
||
} | ||
|
||
static IEnumerable<Type> GetPropertyTypes(Type type) | ||
{ | ||
var result = new HashSet<Type> { type }; | ||
|
||
var properties = type.GetProperties() | ||
.Where(p => !IgnoredTypes.Contains(p.PropertyType)) | ||
.Where(p => p.GetCustomAttribute<XmlIgnoreAttribute>() == null); | ||
|
||
foreach (var property in properties) | ||
{ | ||
var propertyType = property.PropertyType; | ||
if (IsSupportedGenericType(propertyType)) | ||
{ | ||
propertyType = propertyType.GenericTypeArguments.First(); | ||
} | ||
|
||
if (!result.Contains(propertyType)) | ||
{ | ||
result.UnionWith(GetPropertyTypes(propertyType)); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
static bool IsSupportedGenericType(Type propertyType) | ||
{ | ||
return typeof(IEnumerable).IsAssignableFrom(propertyType) && propertyType.IsGenericType && propertyType.GenericTypeArguments.Length == 1; | ||
} | ||
} | ||
|
||
|
||
} |
106 changes: 106 additions & 0 deletions
106
test/ExtendedXmlSerializer.Tests/ExtensionModel/Types/Sources/InspectedPropertyTypesTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Xml.Serialization; | ||
using ExtendedXmlSerializer.ExtensionModel.Types.Sources; | ||
using Xunit; | ||
|
||
namespace ExtendedXmlSerializer.Tests.ExtensionModel.Types.Sources | ||
{ | ||
public class InspectedPropertyTypesTests | ||
{ | ||
[Fact] | ||
public void ShouldHandleSingleProperty() | ||
{ | ||
var types = new InspectedPropertyTypes<Vehicle>(); | ||
|
||
var result = types.Get(); | ||
|
||
Assert.Equal(2, result.Length); | ||
Assert.Contains(result, t => t == typeof(Vehicle)); | ||
Assert.Contains(result, t => t == typeof(Engine)); | ||
} | ||
|
||
|
||
[Fact] | ||
public void ShouldIgnoreExcludedProperties() | ||
{ | ||
var types = new InspectedPropertyTypes<AlmostEmptyClass>(); | ||
|
||
var result = types.Get(); | ||
|
||
Assert.Single(result); | ||
Assert.Contains(result, t => t == typeof(AlmostEmptyClass)); | ||
} | ||
|
||
|
||
|
||
[Fact] | ||
public void SamePropertyAsParentShouldNotCauseStackOverflow() | ||
{ | ||
var types = new InspectedPropertyTypes<Human>(); | ||
|
||
var result = types.Get(); | ||
|
||
Assert.Single(result); | ||
Assert.Contains(result, t => t == typeof(Human)); | ||
} | ||
|
||
[Fact] | ||
public void ShouldHandleListGracefully() | ||
{ | ||
var types = new InspectedPropertyTypes<Zoo>(); | ||
|
||
var result = types.Get(); | ||
|
||
Assert.Equal(2, result.Length); | ||
Assert.Contains(result, t => t == typeof(Zoo)); | ||
Assert.Contains(result, t => t == typeof(Animal)); | ||
} | ||
|
||
class Vehicle | ||
{ | ||
public Engine Engine { get; set; } | ||
} | ||
|
||
class Engine | ||
{ | ||
} | ||
|
||
class AlmostEmptyClass | ||
{ | ||
public int Int { get; set; } | ||
public uint UInt { get; set; } | ||
public string String { get; set; } | ||
public long Long { get; set; } | ||
public ulong ULong { get; set; } | ||
public short Short { get; set; } | ||
public ushort UShort { get; set; } | ||
public double Double { get; set; } | ||
public bool Bool { get; set; } | ||
public decimal Decimal { get; set; } | ||
public byte Byte { get; set; } | ||
public sbyte SByte { get; set; } | ||
public DateTime DateTime { get; set; } | ||
|
||
[XmlIgnore] | ||
public Animal Animal { get; set; } | ||
} | ||
|
||
class Human | ||
{ | ||
public Human Mother { get; set; } | ||
public Human Father { get; set; } | ||
} | ||
|
||
class Zoo | ||
{ | ||
public List<Animal> Animals { get; set; } | ||
} | ||
|
||
class Animal | ||
{ | ||
} | ||
} | ||
|
||
|
||
} |