//public static Type GetFinalType(this ICustomDataTemplate dataTemplate)
    //{
    //    var dataType = (Type) dataTemplate.DataType;
    //    var finalDataType = dataTemplate.GenericArgument() == null
    //        ? dataType
    //        : dataType.Assembly.GetType(
    //            dataType.FullName + "`1").MakeGenericType(dataTemplate.GenericArgument());
    //    return finalDataType;
    //}

    public static bool Matches(this DataTemplate dataTemplate, Object instance)
    {
        if (instance == null || dataTemplate.FinalType() == null)
        {
            return(false);
        }

        var  instanceType = instance.GetType();
        bool result;

        if (!dataTemplate.MatchMap().TryGetValue(instanceType, out result))
        {
            result = dataTemplate.FinalType().IsInstanceOfType(instance);
            if (!result && dataTemplate.GenericArgument() != null)
            {
                var softMatch =
                    instanceType.BaseTypes()
                    .Concat(instanceType.GetInterfaces())
                    .Any(
                        t =>
                        t.IsGenericType &&
                        t.GetGenericTypeDefinition() == dataTemplate.FinalType().GetGenericTypeDefinition() &&
                        (t.GetGenericArguments()
                         .SequenceEqual(new[] { dataTemplate.GenericArgument() },
                                        Api.Create.EqualityComparer <Type>(
                                            (t1, t2) => t1.IsLogicalEqualTo(t2)))));

                result = softMatch;
            }
            dataTemplate.MatchMap().Add(instanceType, result);
        }
        return(result);
    }
        public static Type FinalType(this DataTemplate dataTemplate)
        {
            return(dataTemplate.Get(() =>
            {
                var dataType = (Type)dataTemplate.DataType;



                if (dataTemplate.GenericArgument() == null)
                {
                    return dataType;
                }
                if (dataTemplate.GenericArgumentInnerArgument() == null)
                {
                    return dataType.CreateGenericType(dataTemplate.GenericArgument());
                }

                return dataType.CreateGenericType(
                    dataTemplate.GenericArgument().CreateGenericType(
                        dataTemplate.GenericArgumentInnerArgument()));
            }));
        }