如何检查SignalPayload子类是否实现IConvertible接口及相关问题
Let's tackle your two issues step by step, with corrected and annotated Kotlin code:
1. Check if a KClass<SignalPayload> implements IConvertible
To determine if the given KClass implements the IConvertible interface, we can use Kotlin's reflection API with IConvertible::class.isAssignableFrom(type). This checks if the target type is a subclass or implementation of IConvertible. We'll also improve instance creation to use the primary constructor directly, which is safer than relying on createInstance() for classes that might not have an explicit no-arg constructor.
2. Fix SignalChannel's type parameters and instance logic
Making SignalChannel a generic class with a type constraint that requires the type to extend both SignalPayload and IConvertible ensures full type safety. This avoids unsafe casts and guarantees that setFromPayload can be called on mPayload without runtime errors.
Here's the full corrected code:
sealed class SignalPayload { companion object { fun trueTypeInstance(type: KClass<out SignalPayload>) : SignalPayload? { // Check if the target type implements IConvertible return if (IConvertible::class.isAssignableFrom(type)) { // Use primary constructor to create instance (safer for data classes with defaults) type.primaryConstructor?.call() } else { null // Return null if the type doesn't meet the requirement } } } } object Empty : SignalPayload() data class BadData(val message: String = "BAD") : SignalPayload() { override fun toString(): String { return message } } // Fixed class names to follow Kotlin's PascalCase convention data class PayloadString(private var payload: String = "") : SignalPayload(), IConvertible { override val asBool: Boolean get() = payload.toBoolean() override val asInt: Int get() = payload.toIntOrNull() ?: 0 override val asFloat: Float get() = payload.toFloatOrNull() ?: 0F override val asString: String get() = payload override fun setFromPayload(data: IConvertible) { payload = data.asString } } data class PayloadInt(private var payload: Int = 0) : SignalPayload(), IConvertible { override val asBool: Boolean get() = payload != 0 override val asInt: Int get() = payload override val asFloat: Float get() = payload.toFloat() override val asString: String get() = payload.toString() override fun setFromPayload(data: IConvertible) { payload = data.asInt } } data class PayloadFloat(private var payload: Float = 0F) : SignalPayload(), IConvertible { override val asBool: Boolean get() = payload != 0F override val asInt: Int get() = payload.toInt() override val asFloat: Float get() = payload override val asString: String get() = payload.toString() override fun setFromPayload(data: IConvertible) { payload = data.asFloat } } data class PayloadBool(private var payload: Boolean = false) : SignalPayload(), IConvertible { override val asBool: Boolean get() = payload override val asInt: Int get() = if (payload) 1 else 0 override val asFloat: Float get() = if (payload) 1F else 0F override val asString: String get() = payload.toString() override fun setFromPayload(data: IConvertible) { payload = data.asBool } } interface IConvertible { val asBool: Boolean val asInt: Int val asFloat: Float val asString: String fun setFromPayload(data: IConvertible) } interface IArriving { fun onNewPayload(data: SignalPayload, sender: IArriving?) } // Generic SignalChannel with cross-type constraint for type safety class SignalChannel<T : SignalPayload & IConvertible>( val idx: Int, val type: KClass<T>, val name: String = "" ) : IArriving { var mPayload: SignalPayload = Empty override fun onNewPayload(data: SignalPayload, sender: IArriving?) { // Initialize mPayload if it's still in the default Empty state if (mPayload is Empty) { SignalPayload.trueTypeInstance(type)?.let { mPayload = it } ?: run { // Fallback to BadData if initialization fails mPayload = BadData("Unsupported payload type") } } // Only execute conversion if both payloads implement IConvertible if (mPayload is IConvertible && data is IConvertible) { (mPayload as IConvertible).setFromPayload(data) } else { mPayload = BadData("Cannot convert incoming payload") } } }
Key Improvements:
- Class Naming: Updated class names to follow Kotlin's PascalCase convention for consistency.
- Reflection Safety: Used
primaryConstructor?.call()instead ofcreateInstance()to handle edge cases where classes might not have an explicit no-arg constructor. - Type Safety: The generic
SignalChannelensures only valid types (implementing bothSignalPayloadandIConvertible) can be used, eliminating unsafe casts. - Error Handling: Added fallback logic for failed initialization and invalid payload conversions to make the code more robust.
内容的提问来源于stack exchange,提问作者levWi

