虽然 C# 支持 Java 中的委派和事件,但我们必须使用匿名内部类进行绑定,否则使用反射代码http://oatv.com/pub/a/onjava/2003/05/21/delegates.html。在该页面的评论中有关于 CGLib Multicast Delegates 的提示,但谷歌代码似乎不知道该类的任何示例代码。有没有人有一个工作示例的链接,其他人触手可及?
1 回答
我知道这个问题很老,但也许有一天有人想知道同样的事情。对于类似普通C#
的委托,您可能会使用MethodDelegate
,而不是MulticastDelegate
. 假设,我们有一个简单的 Java POJO bean:
public class SimpleBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
然后我们可以像这样创建一个检测(非反射)委托:
public static interface BeanDelegate {
String getValueFromDelegate();
}
@Test
public void testMethodDelegate() throws Exception {
SimpleBean bean = new SimpleBean();
bean.setValue("Hello world!");
BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(
bean, "getValue", BeanDelegate.class);
assertEquals("Hello world!", delegate.getValueFromDelegate());
}
这个例子有几点需要注意:
工厂方法
MethodDelegate#create
只采用一个方法名称作为其第二个参数。这是MethodDelegate
将为您代理的方法。必须有一个没有为对象定义参数的方法,该方法作为其第一个参数提供给工厂方法。因此,
MethodDelegate
它并不像它可能的那么强大。第三个参数必须是一个只有一个参数的接口。实现了这个
MethodDelegate
接口并且可以被强制转换为它。调用该方法时,它将调用作为第一个参数的对象的代理方法。
有一些缺点/陷阱:
CGlib 为每个代理创建一个新类。最终,这将填满你的永久代堆空间。(从长远来看,这可能会导致问题。)
您不能代理带参数的方法。(这很糟糕。)
如果您的接口接受参数,则方法委托将根本无法正常工作而不会引发异常(返回值将始终为
null
)。如果您的接口需要另一种返回类型(即使那更通用),您将获得一个IllegalArgumentException
. (这很奇怪。)
MulticastDelegate
作品有点不同。这次我们需要一个 bean,它实际上用一个方法实现了一个接口:
public class SimpleMulticastBean implements DelegatationProvider {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public interface DelegatationProvider {
void setValue(String value);
}
这一次,DelegatationProvider
在示例中调用的接口必须提供一个方法(如前所述)。此接口必须由添加到此委托代理的任何对象实现。这可以按如下方式完成:
@Test
public void testMulticastDelegate() throws Exception {
MulticastDelegate multicastDelegate = MulticastDelegate.create(
DelegatationProvider.class);
SimpleMulticastBean first = new SimpleMulticastBean();
SimpleMulticastBean second = new SimpleMulticastBean();
multicastDelegate = multicastDelegate.add(first);
multicastDelegate = multicastDelegate.add(second);
DelegatationProvider provider = (DelegatationProvider)multicastDelegate;
provider.setValue("Hello world!");
assertEquals("Hello world!", first.getValue());
assertEquals("Hello world!", second.getValue());
}
同样,这种实现也有其缺点:
对象需要实现单方法接口。这对于第三方库来说很糟糕,并且当您使用 CGlib 来做一些魔术时,这种魔术会暴露给普通代码时会很尴尬。此外,您可以轻松实现自己的委托(虽然没有字节码,但我怀疑您是否比手动委托更胜一筹)。
当您的委托返回一个值时,您将只收到您添加的最后一个委托的值。所有其他返回值都将丢失(但在某个时候由多播委托检索)。
进一步阅读:我受到启发,并在一篇博客文章中总结了我所知道的关于 cglib 的一切。