Scala 如何在任何对象上使用applyDynamic

Scala 如何在任何对象上使用applyDynamic,scala,dynamic,Scala,Dynamic,我正在考虑使用新类型的Dynamic,但发现一个明显的用例没有得到很好的实现。我正在尝试为面向对象数据库创建方便的包装器。它面临强制转换和可用性问题,因为它序列化和反序列化对象(它的方法返回对象) 第一个问题: 我的数据库的get方法反序列化了一个类型为A的对象。虽然A有一个方法A(),而且我可能在给定的时刻知道,我有一个A,但我不能调用A(),因为java只看到对象。如果“底层”对象真的有这种方法,动态机制会为我尝试吗?还是我必须自己在applyDynamic中处理这种方法?我在REPL中试过

我正在考虑使用新类型的Dynamic,但发现一个明显的用例没有得到很好的实现。我正在尝试为面向对象数据库创建方便的包装器。它面临强制转换和可用性问题,因为它序列化和反序列化对象(它的方法返回对象)

第一个问题: 我的数据库的get方法反序列化了一个类型为A的对象。虽然A有一个方法A(),而且我可能在给定的时刻知道,我有一个A,但我不能调用A(),因为java只看到对象。如果“底层”对象真的有这种方法,动态机制会为我尝试吗?还是我必须自己在applyDynamic中处理这种方法?我在REPL中试过了,但对我来说似乎不行。 如果我必须自己检查,最简单的方法是什么(使用scala的新反射还是不使用),来检查该对象是否有方法“methodname”,如果是,则调用它

被这个吓跑了 我回到java的反射,它可以很容易地完成方法调用部分

我想到了这个:

 scala> import java.lang.reflect.Method
 import java.lang.reflect.Method

 scala> class DynTest3 extends Dynamic {
 | def pee():String = "yuppie"
 |   def execSucced(method: Method, args: Any*):Boolean = return try{method.invoke(args); true} catch { case e: Exception => false }
 | def applyDynamic(methodName : String)(args: Any*){
 |     val succed = classOf[DynTest3].getDeclaredMethods.filter(m => m.getName() == methodName).exists(m => execSucced(m))
 | if (!succed)
 | throw new java.lang.NoSuchMethodException
 | }
 | }
 defined class DynTest3
但是:

scala>valy:Object=new DynTest3
y:对象=DynTest3@74c74b55
scala>y.asInstanceOf[Dynamic].pee()
:11:错误:值applyDynamic不是Dynamic的成员
y、 asInstanceOf[Dynamic].pee()
所以基本上,这不起作用,即使我将其转换为Dynamic。强制转换为Dynamic已经会使整个事情变得毫无用处,因为我想从强制转换中拯救用户。但也许可以创建一个隐式转换any2Dynamic


任何提示?

Scala中的动态是一种简单的编译时重写方案。详细内容在中提供,在这里,我将尝试用不同的语言解释它们

与C#中的
dynamic
引入了元对象的整个基础结构不同,Binder和callsite caching+实现了一个迷你C#编译器,在运行时为重载提供服务,在Scala中,我们决定使用尽可能简单的方法

我已经提到了编译时重写,现在是详细说明的时候了。有几个规则,但让我们来看一看最重要的规则。

如果我们无法编译foo.bar(arg1…argN),并且foo的静态类型是Dynamic的子类型,那么将调用重写为foo.applyDynamic(“bar”)(arg1…argN)。重写的表达式将像往常一样进行类型检查,就好像它是由程序员手动编写的一样

对于
y.asInstanceOf[Dynamic].pee()
,调用的接收方y.asInstanceOf[Dynamic]肯定是一个静态类型,属于动态子类型,因此会触发重写。重写的结果是
y.asInstanceOf[Dynamic].applyDynamic(“pee”)()
。然而,当Scala尝试对这个表达式进行类型检查时,它失败了,因为Dynamic只是一个空的标记特征,它没有定义任何方法


要解决这个问题,您可以强制转换为动态子类型并具有applyDynamic成员的对象(或者您不强制转换,但使API返回的不是Object,而是该对象)。您可以自己编写,也可以使用DynamicProxy(子类化以合并自定义逻辑),我希望它将包含在2.10.0-M5中。

Scala中的Dynamic是一种简单的编译时重写方案。详细内容在中提供,在这里,我将尝试用不同的语言解释它们

与C#中的
dynamic
引入了元对象的整个基础结构不同,Binder和callsite caching+实现了一个迷你C#编译器,在运行时为重载提供服务,在Scala中,我们决定使用尽可能简单的方法

我已经提到了编译时重写,现在是详细说明的时候了。有几个规则,但让我们来看一看最重要的规则。

如果我们无法编译foo.bar(arg1…argN),并且foo的静态类型是Dynamic的子类型,那么将调用重写为foo.applyDynamic(“bar”)(arg1…argN)。重写的表达式将像往常一样进行类型检查,就好像它是由程序员手动编写的一样

对于
y.asInstanceOf[Dynamic].pee()
,调用的接收方y.asInstanceOf[Dynamic]肯定是一个静态类型,属于动态子类型,因此会触发重写。重写的结果是
y.asInstanceOf[Dynamic].applyDynamic(“pee”)()
。然而,当Scala尝试对这个表达式进行类型检查时,它失败了,因为Dynamic只是一个空的标记特征,它没有定义任何方法


要解决这个问题,您可以强制转换为动态子类型并具有applyDynamic成员的对象(或者您不强制转换,但使API返回的不是Object,而是该对象)。您可以自己编写这个东西,也可以使用DynamicProxy(子类化以合并您的自定义逻辑),我希望它将包含在2.10.0-M5中。

这似乎与-我认为
DynamicProxy
是您要找的东西。根据正在设计Scala 2.10宏的Eugene Burmako的说法,该代理目前不可用,但可能在某个时候(希望在2.10决赛中)再次可用,感谢SCIS。同一页上被接受的答案已经很有用了。我会检查一下,但是我在intellij上又遇到了一些问题,代码示例在REPL中无法正常工作。代理就在那里。Chris Hodapp做得很好,从头开始重新创建了代理:.@ib84。如果代码示例在REPL中不起作用,请告诉我,我会解决您的问题。我的电子邮件在个人资料中。它似乎与-我认为
DynamicProxy
是你要找的东西。根据正在设计Scala 2.10宏的Eugene Burmako的说法,该代理目前不可用,但可能在某个时候(希望在2.10决赛中)再次可用,感谢SCIS。同一页上被接受的答案已经很有用了。我会检查一下,但我在intellij上又遇到了一些问题,代码示例无法正常工作
 scala> val y: Object = new DynTest3
 y: Object = DynTest3@74c74b55

 scala> y.asInstanceOf[Dynamic].pee()
 <console>:11: error: value applyDynamic is not a member of Dynamic
          y.asInstanceOf[Dynamic].pee()