-
Notifications
You must be signed in to change notification settings - Fork 935
Description
The static proxy factory may generate duplicated methods in proxies. This does not cause a crash, but instead, the first defined method is executed, ignoring the other ones.
This happen when the proxified type has many methods with the same signature, but coming from interfaces. In such case, these methods are all generated as regular class methods, instead of being generated as explicit interface implementation.
By example, the proxy generated for:
nhibernate-core/src/NHibernate.Test/StaticProxyTest/Model.cs
Lines 28 to 33 in 22cd760
public class InterfacedEntity : IEntity | |
{ | |
public virtual Guid Id { get; set; } | |
public virtual string Name { get; set; } | |
public virtual string Text { get; set; } | |
} |
(IEntity
defines the same members.)
Is currently:
[Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
public class InterfacedEntityProxy : InterfacedEntity, ISerializable, INHibernateProxy, IEntity
{
private ILazyInitializer __lazyInitializer;
private NHibernateProxyFactoryInfo __proxyInfo;
public InterfacedEntityProxy(ILazyInitializer _lazyInitializer, NHibernateProxyFactoryInfo _proxyInfo)
{
this.__lazyInitializer = _lazyInitializer;
this.__proxyInfo = _proxyInfo;
}
public override Guid get_Id()
{
if (this.__lazyInitializer == null)
{
return base.Id;
}
return (Guid)this.__lazyInitializer.get_Identifier();
}
public override void set_Id(Guid guid)
{
if (this.__lazyInitializer == null)
{
base.Id = guid;
return;
}
this.__lazyInitializer.Initialize();
this.__lazyInitializer.set_Identifier(guid);
((InterfacedEntity)this.__lazyInitializer.GetImplementation()).Id = guid;
}
public override string get_Name()
{
if (this.__lazyInitializer == null)
{
return base.Name;
}
return ((InterfacedEntity)this.__lazyInitializer.GetImplementation()).Name;
}
public override void set_Name(string name)
{
if (this.__lazyInitializer == null)
{
base.Name = name;
return;
}
((InterfacedEntity)this.__lazyInitializer.GetImplementation()).Name = name;
}
public override string get_Text()
{
if (this.__lazyInitializer == null)
{
return base.Text;
}
return ((InterfacedEntity)this.__lazyInitializer.GetImplementation()).Text;
}
public override void set_Text(string text)
{
if (this.__lazyInitializer == null)
{
base.Text = text;
return;
}
((InterfacedEntity)this.__lazyInitializer.GetImplementation()).Text = text;
}
public override string ToString()
{
if (this.__lazyInitializer == null)
{
return base.ToString();
}
return ((object)this.__lazyInitializer.GetImplementation()).ToString();
}
ILazyInitializer INHibernateProxy.get_HibernateLazyInitializer()
{
return this.__lazyInitializer;
}
public override Guid get_Id()
{
if (this.__lazyInitializer == null)
{
return base.Id;
}
return ((IEntity)this.__lazyInitializer.GetImplementation()).Id;
}
public override void set_Id(Guid id)
{
if (this.__lazyInitializer == null)
{
base.Id = id;
return;
}
((IEntity)this.__lazyInitializer.GetImplementation()).Id = id;
}
public override string get_Name()
{
if (this.__lazyInitializer == null)
{
return base.Name;
}
return ((IEntity)this.__lazyInitializer.GetImplementation()).Name;
}
public override void set_Name(string name)
{
if (this.__lazyInitializer == null)
{
base.Name = name;
return;
}
((IEntity)this.__lazyInitializer.GetImplementation()).Name = name;
}
public override string get_Text()
{
if (this.__lazyInitializer == null)
{
return base.Text;
}
return ((IEntity)this.__lazyInitializer.GetImplementation()).Text;
}
public override void set_Text(string text)
{
if (this.__lazyInitializer == null)
{
base.Text = text;
return;
}
((IEntity)this.__lazyInitializer.GetImplementation()).Text = text;
}
public InterfacedEntityProxy(SerializationInfo serializationInfo, StreamingContext streamingContext)
{
}
[SecurityCritical]
public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext context)
{
serializationInfo.SetType(typeof(NHibernateProxyObjectReference));
new NHibernateProxyObjectReference(this.__proxyInfo, this.__lazyInitializer.get_Identifier(), this.__lazyInitializer.get_IsUninitialized() ? null : this.__lazyInitializer.GetImplementation()).GetObjectData(serializationInfo, context);
}
}
It has two get_Id
, but only the first one will be called when getting the Id
, even if we do that through IEntity
. The second one has a different implementation which would cause a lazy initialization.
Fixing this will be a possible breaking changes for cases where the user is relying on this bug, as in #2052.
Possible breaking change: a class proxy for a class having an explicitly implemented interface declaring a member with the same name than the class id will now trigger a lazy load if the interface "id" is accessed.