2013-03-24 3 views
3

스칼라 리플렉션을 사용하여 특성 케이스 클래스를 정의하려고하고 있는데이 클래스의 동반 클래스가 "내보내기 가능"(예 : Map [String, Any]) 및 "가져 오기 가능" 같은에서. 최상위 사례 클래스에서는 잘 작동하지만 내부 클래스에서는 작동하지 않습니다. InstanceMirror에 반영 할 수있는 엔 클로징 인스턴스에 이미 핸들이있는 경우 내부 클래스를 리플렉션 방식으로 인스턴스화하는 방법을 알고 있지만 현재로서는 최상위 또는 내부 클래스에서 나중에 구현 될 특성을 작성하고 있습니다. .스칼라 리플렉션으로 인스턴스를 둘러싼 경우 찾기 (스 프레어 리플렉션으로)

동반자와 생성 된 인스턴스가 동일한 인 클로징 인스턴스를 공유하는 한이 작업을 수행 할 수 있어야합니다. 그러나 동반자의 사례를 반영하는 방법을 반영하는 방법을 파악할 수 없었습니다. 여기

import scala.reflect.runtime.universe._; 

trait CompanionOfReflectiveConstructable[T] { 
    def tType : Type; 

    lazy val mirror  : Mirror  = runtimeMirror(this.getClass.getClassLoader); 
    lazy val ctorDecl  : Symbol  = tType.declaration(nme.CONSTRUCTOR); 
    lazy val ctor   : MethodSymbol = ctorDecl.asMethod; 
    lazy val tClass  : ClassSymbol = tType.typeSymbol.asClass; 
    lazy val tClassMirror : ClassMirror = mirror.reflectClass(tClass); 
    lazy val ctorF  : MethodMirror = tClassMirror.reflectConstructor(ctor); 

    // in real-life, i'd derive arguments from ctor.paramss 
    // but to highlight our issue, we'll assume a no arg constructor 
    def createInstance : T = ctorF().asInstanceOf[T]; 
} 

trait ReflectiveConstructable; 

object Test1 extends CompanionOfReflectiveConstructable[Test1] { 
    def tType = typeOf[Test1]; 
} 
class Test1 extends ReflectiveConstructable; 

class Outer { 
    object Test2 extends CompanionOfReflectiveConstructable[Test2] { 
    def tType = typeOf[Test2]; 
    } 
    class Test2 extends ReflectiveConstructable; 
} 

일어나는 내용은 다음과 같습니다

여기에 내가 뭘하려고 오전의 예를 단순화하는 방법 및 발생하는 문제입니다.

scala> Test1.createInstance 
res0: Test1 = [email protected] 

scala> (new Outer).Test2.createInstance 
scala.ScalaReflectionException: class Test2 is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror 
     at scala.reflect.runtime.JavaMirrors$JavaMirror.ErrorInnerClass(JavaMirrors.scala:126) 
... 

Test1 훌륭한 작품입니다. Test2의 문제점은 분명합니다. 최상위 미러가 아닌 InstanceMirror를 통해 ClassMirror를 가져와야합니다. (here, herehere을 참조하십시오.)하지만 CompanionOfReflectiveConstructable 내에서 내가 내부인지 또는 내 인스 턴싱 인스턴스가 적절한 작업을 조건부로 수행하는지 확인하는 방법을 알지 못합니다. 누구든지이 작업을 수행하는 방법을 알고 있습니까?

감사합니다.

답변

1

여기서 주목할 주요 문제점은 내부 클래스의 부속 객체 내부에서 리플렉션을 사용하고 있다는 것입니다. Test2 클래스에는 외부 클래스를 포함하는 $ outer라는 필드가 정의되어 있지만 Test2 동반자 개체에서는 Test2를 만드는 데 필요한 외부 인스턴스를 가져올 수 없습니다. 내가 볼 수있는 주변에만 작동, 당신은 동반자 특성이야에 옵션 인스턴스를 전달하는 것입니다 :의 Test2를 동반자 개체에서 외부 인스턴스를 얻을 수있는 방법이 있다면

trait CompanionOfReflectiveConstructable[T] { 
    def tType: Type 

    def outer: Option[AnyRef] = None 

    val mirror = runtimeMirror(this.getClass.getClassLoader) 
    val tClassMirror = outer 
    .map(a => mirror.reflect(a).reflectClass(tType.typeSymbol.asClass)) 
    .getOrElse(mirror.reflectClass(tType.typeSymbol.asClass)) 

    val ctorF = tClassMirror.reflectConstructor(tType.declaration(nme.CONSTRUCTOR).asMethod) 

    // in real-life, i'd derive arguments from ctor.paramss 
    // but to highlight our issue, we'll assume a no arg constructor 
    def createInstance: T = ctorF().asInstanceOf[T] 
} 

trait ReflectiveConstructable 

class Test1 extends ReflectiveConstructable 

object Test1 extends CompanionOfReflectiveConstructable[Test1] { 
    def tType = typeOf[Test1] 
} 

class Outer { 

    object Test2 extends CompanionOfReflectiveConstructable[Test2] { 
    def tType = typeOf[Test2] 
    override def outer = Option(Outer.this) 
    } 

    class Test2 extends ReflectiveConstructable 
} 

그것은 좋은 것입니다하지만, 슬프게도 런타임에는 사용할 수 없습니다.

+0

이렇게하면 좋은 해결책이 될 수 있으며 최선의 방법이 될 수 있습니다. 하지만 그것은 해결책이 아닙니다. 둘러싸인 인스턴스를 반사적으로 찾는 수단이 아닙니다. (스칼라 리플렉션이 경로 종속 유형을 정확하게 처리하지 않는 것처럼 보입니다.) 예를 들어, Test2 인스턴스의 경우 ctor.owner.owner는 어떤 식 으로든 인스턴스를 나타내지 만 대신 클래스입니다. 반사는 Outer # Test2 형식을 볼 수 있지만 o.Test2 형식은 볼 수없는 것처럼 보입니다. o는 외부의 인스턴스입니다. –

+0

따라서 내부 컴패니언 개체가 컴파일 될 때 , 내부 클래스와 같은 외부 클래스에 대한 참조를 얻지는 않습니다 (기본 생성자의 일부입니다). 외부 인스턴스를 보면 모듈 (컴패니언 객체)에 대한 휘발성 참조가 있지만 모듈 외부 클래스에 대한 참조가 없으므로 이제 특성이 내부 클래스에 적용되므로 외부 클래스에 대한 참조를 얻을 수있는 방법이 없습니다. 스칼라 매크로를 사용하여이 문제를 해결할 수도 있습니다. 외부 클래스 인스턴스를 참조하는 것이 가능하다고 생각합니다. 어떤 종류의 반영을 통해. – Noah

+0

그래서 바이트 코드를 따르려고하지는 않았지만 내부 모듈이 둘러싼 인스턴스를 참조하지 않는다는 사실을 _unconditionally_ true 일 수는 없습니까? 둘러싼 인스턴스 멤버를 참조 할 경우 어떻게됩니까? 그 당시에는 경로가 있어야합니다. 어쨌든 리플렉션은 내부 모듈과 경로 종속 유형에 대해 실제로 수행해야하는 작업을 수행 할 수 없다는 것을 의미합니다. (나는 대답을 받아들이지 않아서 유감이지만 최고 등급의 반액을 받기를 바란다.하지만 문제는 해결되지 않았다. 아마도 불용성이기 때문일 것이다.) –

관련 문제