swift 从“X.Type”强制转换为不相关的类型“Y.Type”总是失败

toiithl6  于 2023-03-22  发布在  Swift
关注(0)|答案(1)|浏览(109)

我试图创建一个通用的fetch函数来从Core Data中提取任何实体,然后将其转换为我的一个数据传输对象。但我被如何从我的协议DTO转换为DTO的特定实现所困。

public func getEntity<T: DTOConvertible, Y: DTO>(CDtype: T.Type, id: CVarArg, DTOType: Y.Type) -> Y.Type {
    let request = T.fetchRequest() as! NSFetchRequest<T>
    request.fetchLimit = 1
    let predicate = NSPredicate(format: "id == %@", id)
    request.predicate = predicate
    
    guard let entityCD = try? moc.fetch(request).first else { return Y.GetDefaultInstance() as! Y.Type }
    
    return entityCD.ToDTO() as! Y.Type //error here
}

我已经将DTOConvertible协议添加到Core Data类中,以添加ToDTO()转换器函数。

protocol DTOConvertible: NSManagedObject {
    func ToDTO() -> any DTO
}

extension ExerciseCD : Identifiable, DTOConvertible {
    public func ToDTO() -> DTO {
        return Exercise(ExerciseId: self.exerciseId, ExerciseName: self.exerciseName)
    }
}

我的所有DTO结构都符合DTO协议。

public protocol DTO {
    static func GetDefaultInstance() -> Self
}

public struct Exercise: Codable, Identifiable, DTO {
    public var id: String { return ExerciseId }
    public var ExerciseId: String
    public var ExerciseName: String
    
    public static func GetDefaultInstance() -> Exercise {
        return Exercise(ExerciseId: "", ExerciseName: "")
    }
}

如果我在ExerciseCD上更改ToDTO()的实现以返回Exercise(特定的DTO),那么编译器会抱怨ExerciseCD不符合DTOConvertible协议。但是即使Exercise符合DTO,我也不能从DTO转换为Exercise。有没有办法解决这个问题?

syqv5f0l

syqv5f0l1#

您可以使用T.SomeTypeAlias来代替Y

protocol DTOConvertible: NSManagedObject {
    associatedtype D: DTO
    func toDTO() -> D
}

然后在getEntity

public func getEntity<T: DTOConvertible>(CDtype: T.Type, id: CVarArg) -> T.D { //Simplify this line
    let request = T.fetchRequest() as! NSFetchRequest<T>
    request.fetchLimit = 1
    let predicate = NSPredicate(format: "id == %@", id)
    request.predicate = predicate
    
    guard let entityCD = try? moc.fetch(request).first else {
        return T.D.getDefaultInstance() //Use T.D to access default
    }
    
    return entityCD.toDTO() //Convert
}

那么实体只需要一个微小的改变

extension ExerciseCD : Identifiable, DTOConvertible {
    func toDTO() -> Exercise  { //Should start with lowercase and return type.
        return Exercise(exerciseId: self.objectID.uriRepresentation().absoluteString, exerciseName: self.objectID.uriRepresentation().absoluteString)
    }
}

public protocol DTO {
    static func getDefaultInstance() -> Self //Should start with lowercase
}

public struct Exercise: Codable, Identifiable, DTO {
    public var id: String { return exerciseId }
    public var exerciseId: String //Swift convention variables should start with lowercase
    public var exerciseName: String //Swift convention variables should start with lowercase
    
    public static func getDefaultInstance() -> Exercise { //Swift convention methods/functions should start with lowercase
        return Exercise(exerciseId: "", exerciseName: "")
    }
}

相关问题