1

我正在尝试获取拥有伴随对象的类,以便我可以在伴随对象中使用内联技术创建记录器,但引用正在记录的主类而不是伴随对象。

问题是我找不到获得伴生对象所有者的方法,我该怎么做?

fun Logger(c: Class<*>): Logger {
    var c2 = c
    val k = c.kotlin
    if (k.isCompanion) {
        c2 = k.<opposite of what companionObject does>.java
    }

    // Calls a factory, reuse the same instance if it already exists
    return RootLogger.getChild(c2)
}

@Suppress("NOTHING_TO_INLINE")
inline fun Logger(): Logger {
    return Logger(MethodHandles.lookup().lookupClass())
}

预期的用例:

A:

class SomeClass {
    companion object {
        // Logger is inside a companion object
        // But it must be the same as if it were created directly inside `SomeClass`
        private val log = Logger()
    }

    fun someFun() = log.info("Hello")
}

乙:

// can be object or anything else
class SomeClass {
    // The same object is returned to all instances and would be the same object
    // as if it were inside a companion object
    private val log = Logger()

    fun someFun() = log.info("Hello")
}
4

1 回答 1

0

在JVM环境中可以通过以下方式实现:

k.java.enclosingClass.kotlin

所以函数将是:

fun Logger(c: Class<*>): Logger {
    var c2 = c
    val k = c.kotlin
    if (k.isCompanion) {
        c2 = k.java.enclosingClass
    }

    // Calls a factory, reuse the same instance if it already exists
    return RootLogger.getChild(c2)
}

可以通过以下方式进行测试:

internal class LoggerTest {
    @Test
    internal fun testUseCaseA() {
        val fqn = UseCaseA::class.qualifiedName
        assertEquals(fqn, UseCaseA.log.name)

        val log = Logger(UseCaseA::class.java)
        assertEquals(fqn, log.name)
        assertSame(UseCaseA.log, log)

        val log2 = Logger(UseCaseA.Companion::class.java)
        assertEquals(fqn, log2.name)
        assertSame(log, log2)
    }

    @Test
    internal fun testUseCaseB() {
        val fqn = UseCaseB::class.qualifiedName
        val b1 = UseCaseB()
        assertEquals(fqn, b1.log.name)

        val log = Logger(UseCaseB::class.java)
        assertEquals(fqn, log.name)
        assertSame(b1.log, log)

        val b2 = UseCaseB()
        assertEquals(fqn, b2.log.name)
        assertSame(b2.log, log)
    }

    private class UseCaseA {
        companion object {
            val log = Logger()
        }
    }

    private class UseCaseB {
        val log = Logger()
    }
}
于 2022-02-17T14:40:52.427 回答