![](/img/trans.png)
[英]Is there a way to decompile the dynamic proxy classes that are generated by NHibernate?
[英]Identifying NHibernate proxy classes
我不是NHibernate用户; 我写了一个序列化实用程序库。 用户已记录一个功能请求,我应该处理NHibernate代理类,将它们视为与实际类型相同。 目前,我的代码将它们视为意外继承,并抛出异常。
代码不会提前知道NHibernate(包括没有引用,但我不是反射;-p)
是否有一种强大/有保证的方法来检测此类代理类型? 显然DataContractSerializer
处理这个问题,所以我希望它非常简单。 也许有些界面或[attribute]
装饰。
此外,在反序列化期间; 目前我将创建原始类型(不是NHibernate类型)。 这是否适用于持久性目的? 或者是否需要代理类型? 如果是后者; 创建代理类型的实例需要什么?
您可以通过将类转换为( INHibernateProxy
) INHibernateProxy
来检测类是否是NHibernate代理。
如果您需要获取基础“真实”对象,请使用:
Session.GetSessionImplementation().PersistenceContext.Unproxy(proxiedObject)
您不需要测试代理来调用Unproxy
; 如果它不是代理,它返回原始参数。
编辑:我现在使用不同的方法来获取底层对象,主要是为了解决延迟加载和继承: http : //sessionfactory.blogspot.com/2010/08/hacking-lazy-loaded-inheritance.html
我猜你真的不想访问实际的Nhibernate会话。 此代码可能更符合您的需求:
/// <summary>
/// Returns the real type of the given proxy. If the object is not a proxy, it's normal type is returned.
/// </summary>
internal static Type GetRealType(this object proxy)
{
if (proxy is INHibernateProxy)
{
var lazyInitialiser = ((INHibernateProxy)proxy).HibernateLazyInitializer;
return lazyInitialiser.PersistentClass;
}
else
{
return proxy.GetType();
}
}
希望有所帮助。
NHibernate提供了一个工具,您可以在其中提供类型(代理与否),并返回实际类型。 (我正在使用NHibernate 3)
这是你如何使用它:
var realType = NHibernate.NHibernateUtil.GetClass(proxyInstance);
希望这会有所帮助:D
NHibernate在运行时创建(代理)原始实体的子类,以便能够进行延迟加载。 它只能执行此操作,因为您必须将所有属性标记为“虚拟”。 我想不出你如何能够检测到一个对象是一个代理而不是任何其他类型的子类 - 当然不是通用的方式。 我只能假设您的代码在这种情况下抛出异常,因为正在(反)序列化的实际类没有标记为可序列化。 我认为你唯一能做的就是放松你的验证或允许子类的序列化,如果它覆盖了它的基类的所有属性。
反序列化为原始类型将没有问题。
NHibernate 2.1+允许通过配置设置动态代理提供程序。 我所知道的实现是Castle(默认),LinFu和Spring。 NHibernate不需要接口或属性。 我认为这使得可靠地检测对象是否是代理是不可能的。
当s1mm0t回答时,在反序列化时创建实际类型很好。
如果您正在编写通用序列化实用程序库,我认为您根本不应该处理该特定情况。 您的代码不应该依赖于NHibernate。 您应该做的是提供客户端代码可以用来影响库操作的钩子。
迭代的方法在尝试确定它的类型之前完全加载对象 - 这绝对是最通用的方法,但如果代理已知具体类型,则可能不需要加载对象。
在事先知道具体类型的情况下,Vijay的方法更快 - 但正如Diego所指出的那样,在某些情况下,该信息不可用,因为尚未加载确定确切类型所需的信息。
考虑到这两种情况,我想出了以下内容:
https://gist.github.com/1089489
有趣的是这个:
if (entity is INHibernateProxy)
{
var lazyInitialiser = ((INHibernateProxy)entity).HibernateLazyInitializer;
var type = lazyInitialiser.PersistentClass;
if (type.IsAbstract || type.GetNestedTypes().Length > 0)
return Service.Session.GetSessionImplementation().PersistenceContext.Unproxy(entity).GetType();
else // we don't need to "unbox" the Proxy-object to get the type
return lazyInitialiser.PersistentClass;
}
return entity.GetType();
这首先检查代理后面的类型是否是抽象的,并使用Vijay或Diego的方法,具体取决于具体类型是否已知。
换句话说,如果Proxy后面的类型不是具体类型,或者可能是子类型,它只加载对象。
我做了一个快速的单元测试,以证明这是有效的,但我不认为我已经测试了所有可能的情况 - 我相信这个想法是合理的,但我想听听Diego和Vijay或其他人的评论。
谢谢!
编辑:发布上面的要点的更新,使用另一个可用于Unproxy()实体的通用方法 - 在某些情况下,您可能必须这样做...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.