     
     /// Unbox a required raw type
     public func unbox<T: UnboxableRawType>(key: String, isKeyPath: Bool = true) throws -> T {
-        if let rawValue = UnboxValueResolver<T>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath) {
-            return rawValue
-        }
-        
-        let transformedString = UnboxValueResolver<String>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: {
-            return T.transform(unboxedString: $0)
-        })
-        
-        if let transformedString = transformedString {
-            return transformedString
-        }
-        
-        return try UnboxValueResolver<Int>(self).resolveRequiredValueForKey(key: key, isKeyPath: isKeyPath, transform: {
-            return T.transform(unboxedInt: $0)
-        })
+        return try UnboxValueResolver<Any>(self).resolveRequiredValueForKey(key: key, isKeyPath: isKeyPath, transform: T.unbox)
     }
     
     /// Unbox an optional raw type
     public func unbox<T: UnboxableRawType>(key: String, isKeyPath: Bool = true) -> T? {
-        if let rawValue = UnboxValueResolver<T>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath) {
-            return rawValue
-        }
-        
-        let transformedString = UnboxValueResolver<String>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: {
-            return T.transform(unboxedString: $0)
-        })
-        
-        if let transformedString = transformedString {
-            return transformedString
-        }
-        
-        return UnboxValueResolver<Int>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: {
-            return T.transform(unboxedInt: $0)
-        })
+        return UnboxValueResolver<Any>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: T.unbox)
     }
     
     /// Unbox a required Array containing values of a raw type
-    public func unbox<T: UnboxableRawType>(key: String, isKeyPath: Bool = true) throws -> [T] {
-        if let rawValueArray = UnboxValueResolver<[T]>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath) {
-            return rawValueArray
-        }
-        
-        let transformedStringArray = UnboxValueResolver<[String]>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: { stringArray -> [T]? in
-            var transformedStringArray = [T]()
-            for string in stringArray {
-                guard let transformedUnboxedString = T.transform(unboxedString: string) else { return nil }
-                transformedStringArray.append(transformedUnboxedString)
-            }
-            return transformedStringArray
-        })
-        
-        if let transformedStringArray = transformedStringArray {
-            return transformedStringArray
-        }
-        
-        return try UnboxValueResolver<[T]>(self).resolveRequiredValueForKey(key: key, isKeyPath: isKeyPath)
+    public func unbox<T: UnboxableRawType>(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) throws -> [T] {
+        let transform = T.makeArrayTransformClosure(allowInvalidElements: allowInvalidElements)
+        return try UnboxValueResolver<[Any]>(self).resolveRequiredValueForKey(key: key, isKeyPath: isKeyPath, transform: transform)
     }
     
     /// Unbox an optional Array containing values of a raw type
-    public func unbox<T: UnboxableRawType>(key: String, isKeyPath: Bool = true) -> [T]? {
-        return UnboxValueResolver<[T]>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath)
+    public func unbox<T: UnboxableRawType>(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) -> [T]? {
+        let transform = T.makeArrayTransformClosure(allowInvalidElements: allowInvalidElements)
+        return UnboxValueResolver<[Any]>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: transform)
     }
     
     /// Unbox a required Array of collections

}

/// Protocol used to enable any type as being unboxable with a certain formatter type
public protocol UnboxableWithFormatter: UnboxCompatibleType {
    /// The type of formatter to use to format an unboxed value into a value of this type
    associatedtype UnboxFormatterType: UnboxFormatter
}

    
    /// Format an unboxed value into another value (or nil if the formatting failed)
    func format(unboxedValue: UnboxRawValueType) -> UnboxFormattedType?
}

// MARK: - Default protocol implementations

public extension UnboxableRawType {
    static func unbox(value: Any) throws -> Self? {
        if let matchedValue = value as? Self {
            return matchedValue
        }
        
        if let string = value as? String {
            return self.transform(unboxedString: string)
        }

        if let int = value as? Int {
            return self.transform(unboxedInt: int)
        }

        return nil
    }
}

public extension UnboxableByTransform {
    static func unbox(value: Any) throws -> Self? {
        guard let rawValue = value as? UnboxRawValueType else {
            return nil
        }
        
        return self.transform(unboxedValue: rawValue)
    }
}

public extension UnboxableEnum {
    static func unbox(value: Any) throws -> Self? {
        guard let rawValue = value as? RawValue else {
            return nil
        }
        
        return self.init(rawValue: rawValue)
    }
}

// MARK: - Extensions
