tools/AutoMapper/TypePair.cs (146 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using AutoMapper.Configuration;
namespace AutoMapper
{
[DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")]
public struct MapRequest : IEquatable<MapRequest>
{
public TypePair RequestedTypes { get; }
public TypePair RuntimeTypes { get; }
public ITypeMapConfiguration InlineConfig { get; }
public MapRequest(TypePair requestedTypes, TypePair runtimeTypes)
: this(requestedTypes, runtimeTypes, new MapperConfiguration.DefaultTypeMapConfig(requestedTypes))
{
}
public MapRequest(TypePair requestedTypes, TypePair runtimeTypes, ITypeMapConfiguration inlineConfig)
{
RequestedTypes = requestedTypes;
RuntimeTypes = runtimeTypes;
InlineConfig = inlineConfig;
}
public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes);
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is MapRequest && Equals((MapRequest) obj);
}
public override int GetHashCode() => HashCodeCombiner.Combine(RequestedTypes, RuntimeTypes);
public static bool operator ==(MapRequest left, MapRequest right) => left.Equals(right);
public static bool operator !=(MapRequest left, MapRequest right) => !left.Equals(right);
}
[DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")]
public struct TypePair : IEquatable<TypePair>
{
public static bool operator ==(TypePair left, TypePair right) => left.Equals(right);
public static bool operator !=(TypePair left, TypePair right) => !left.Equals(right);
public TypePair(Type sourceType, Type destinationType)
{
SourceType = sourceType;
DestinationType = destinationType;
}
public static TypePair Create<TSource>(TSource source, Type sourceType, Type destinationType)
{
if(source != null)
{
sourceType = source.GetType();
}
return new TypePair(sourceType, destinationType);
}
public static TypePair Create<TSource, TDestination>(TSource source, TDestination destination, Type sourceType, Type destinationType)
{
if(source != null)
{
sourceType = source.GetType();
}
if(destination != null)
{
destinationType = destination.GetType();
}
return new TypePair(sourceType, destinationType);
}
public Type SourceType { get; }
public Type DestinationType { get; }
public bool Equals(TypePair other) => SourceType == other.SourceType && DestinationType == other.DestinationType;
public override bool Equals(object other) => other is TypePair && Equals((TypePair)other);
public override int GetHashCode() => HashCodeCombiner.Combine(SourceType, DestinationType);
public TypePair? GetOpenGenericTypePair()
{
var isGeneric = SourceType.IsGenericType() || DestinationType.IsGenericType();
if (!isGeneric)
return null;
var sourceGenericDefinition = SourceType.IsGenericType() ? SourceType.GetGenericTypeDefinition() : SourceType;
var destGenericDefinition = DestinationType.IsGenericType() ? DestinationType.GetGenericTypeDefinition() : DestinationType;
var genericTypePair = new TypePair(sourceGenericDefinition, destGenericDefinition);
return genericTypePair;
}
public IEnumerable<TypePair> GetRelatedTypePairs()
{
var @this = this;
var subTypePairs =
from destinationType in GetAllTypes(DestinationType)
from sourceType in GetAllTypes(@this.SourceType)
select new TypePair(sourceType, destinationType);
return subTypePairs;
}
private static IEnumerable<Type> GetAllTypes(Type type)
{
var typeInheritance = type.GetTypeInheritance();
foreach(var item in typeInheritance)
{
yield return item;
}
var interfaceComparer = new InterfaceComparer(type);
var allInterfaces = type.GetTypeInfo().ImplementedInterfaces.OrderByDescending(t => t, interfaceComparer);
foreach(var interfaceType in allInterfaces)
{
yield return interfaceType;
}
}
private class InterfaceComparer : IComparer<Type>
{
private readonly List<TypeInfo> _typeInheritance;
public InterfaceComparer(Type target)
{
_typeInheritance = target.GetTypeInheritance().Select(type => type.GetTypeInfo()).Reverse().ToList();
}
public int Compare(Type x, Type y)
{
var xLessOrEqualY = x.IsAssignableFrom(y);
var yLessOrEqualX = y.IsAssignableFrom(x);
if (xLessOrEqualY & !yLessOrEqualX)
{
return -1;
}
if (!xLessOrEqualY & yLessOrEqualX)
{
return 1;
}
if (xLessOrEqualY & yLessOrEqualX)
{
return 0;
}
var xFirstIntroduceTypeIndex = _typeInheritance.FindIndex(type => type.ImplementedInterfaces.Contains(x));
var yFirstIntroduceTypeIndex = _typeInheritance.FindIndex(type => type.ImplementedInterfaces.Contains(y));
if (xFirstIntroduceTypeIndex < yFirstIntroduceTypeIndex)
{
return -1;
}
if (yFirstIntroduceTypeIndex > xFirstIntroduceTypeIndex)
{
return 1;
}
return 0;
}
}
}
public static class HashCodeCombiner
{
public static int Combine<T1, T2>(T1 obj1, T2 obj2) =>
CombineCodes(obj1.GetHashCode(), obj2.GetHashCode());
public static int CombineCodes(int h1, int h2) => ((h1 << 5) + h1) ^ h2;
}
}