c# - the - ¿Cómo me dice la reflexión cuándo una propiedad está ocultando un miembro heredado con la palabra clave ''nueva''?
inherited method c# (4)
Entonces si tengo:
public class ChildClass : BaseClass
{
public new virtual string TempProperty { get; set; }
}
public class BaseClass
{
public virtual string TempProperty { get; set; }
}
¿Cómo puedo usar la reflexión para ver que ChildClass está ocultando la implementación base de TempProperty?
Me gustaría que la respuesta sea agnóstica entre c # y vb.net
Corrección, si está utilizando VB la propiedad que está buscando es "IsHideBySig". Esto será falso en el caso de que la palabra clave "nueva" se usara para definir un método / propiedad.
En el caso de C #, ambas instancias se generan como "hidebysig". Gracias por señalar eso, Greg. No me di cuenta de que solo probé esto en VB. Aquí hay un ejemplo de código VB que reproducirá este comportamiento.
Module Module1
Class Foo
Public Function SomeFunc() As Integer
Return 42
End Function
End Class
Class Bar
Inherits Foo
Public Shadows Function SomeFunc() As Integer
Return 36
End Function
End Class
Sub Main()
Dim type = GetType(Bar)
Dim func = type.GetMethod("SomeFunc")
Stop
End Sub
End Module
No parece que el reflejo te dé esto por defecto, así que tendrás que hacer tu propio:
public static bool IsHidingMember( this PropertyInfo self )
{
Type baseType = self.DeclaringType.BaseType;
PropertyInfo baseProperty = baseType.GetProperty( self.Name, self.PropertyType );
if ( baseProperty == null )
{
return false;
}
if ( baseProperty.DeclaringType == self.DeclaringType )
{
return false;
}
var baseMethodDefinition = baseProperty.GetGetMethod().GetBaseDefinition();
var thisMethodDefinition = self.GetGetMethod().GetBaseDefinition();
return baseMethodDefinition.DeclaringType != thisMethodDefinition.DeclaringType;
}
Sin embargo, no estoy seguro de cómo funcionará esto con las propiedades indexadas.
Nunca hice lo que intentas hacer, pero el método MethodInfo.GetBaseDefinition () parece ser lo que estás buscando.
Devuelve el MethodInfo que este método está anulando.
Desde MSDN:
Si se especifica un método determinado con la palabra clave nueva (como en el lote de noticias como se describe en Tipo de miembros), se devuelve el método proporcionado.
Tendremos que tratar en términos de los métodos de la propiedad aquí en lugar de la propiedad en sí, porque son los métodos get / set de la propiedad los que realmente se anulan en lugar de la propiedad en sí misma. Usaré el método get ya que nunca debería tener una propiedad sin una, aunque una solución completa debería verificar la falta de una.
Mirando el IL emitido en varios casos, el método ''get'' de la propiedad base tendrá los tokens de metadatos (esto es del compilador C #; otros pueden no emitir el hidebysig
dependiendo de su método que hidebysig
semántica, en cuyo caso el método sería hide-by-name):
non-virtual : .method public hidebysig specialname instance
virtual : .method public hidebysig specialname newslot virtual instance
El derivado tendrá los siguientes tokens:
override : .method public hidebysig specialname virtual instance
new : .method public hidebysig specialname instance
new virtual : .method public hidebysig specialname newslot virtual instance
Entonces, podemos ver a partir de esto que no es posible distinguir puramente de los tokens de metadatos del método si es new
porque el método base no virtual tiene los mismos tokens que el new
método no virtual, y el método base virtual tiene el mismos tokens que el new virtual
método new virtual
.
Lo que podemos decir es que si el método tiene el token virtual
pero no el token del newslot
entonces anula un método base en lugar de sombrearlo, es decir,
var prop = typeof(ChildClass).GetProperty("TempProperty");
var getMethod = prop.GetGetMethod();
if ((getMethod.Attributes & MethodAttributes.Virtual) != 0 &&
(getMethod.Attributes & MethodAttributes.NewSlot) == 0)
{
// the property''s ''get'' method is an override
}
Suponiendo, entonces, que encontramos que el método ''get'' no es una anulación, queremos saber si hay una propiedad en la clase base que está sombreando. El problema es que debido a que el método se encuentra en una ranura de tabla de método diferente, en realidad no tiene ninguna relación directa con el método que está sombreando. Entonces, lo que realmente estamos diciendo es "¿el tipo de base tiene algún método que cumpla con los criterios de sombreado?", Que varía según si el método es hidebysig
o hide-by-name.
Para el primero, debemos verificar si la clase base tiene algún método que coincida exactamente con la firma, mientras que para este último necesitamos verificar si tiene algún método con el mismo nombre, por lo que continuamos con el código anterior:
else
{
if (getMethod.IsHideBySig)
{
var flags = getMethod.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
flags |= getMethod.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
var paramTypes = getMethod.GetParameters().Select(p => p.ParameterType).ToArray();
if (getMethod.DeclaringType.BaseType.GetMethod(getMethod.Name, flags, null, paramTypes, null) != null)
{
// the property''s ''get'' method shadows by signature
}
}
else
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
if (getMethod.DeclaringType.BaseType.GetMethods(flags).Any(m => m.Name == getMethod.Name))
{
// the property''s ''get'' method shadows by name
}
}
}
Creo que esto es la mayor parte del camino, pero todavía no creo que sea exactamente correcto. Para empezar, no estoy totalmente familiarizado con el ocultamiento por nombre ya que C # no lo soporta y eso es prácticamente todo lo que uso, por lo que podría estar equivocado en el código que indica que un método de instancia podría sombrear uno estático. Tampoco sé sobre el tema de sensibilidad de mayúsculas y minúsculas (por ejemplo, en VB podría un método llamado Foo
shadow un método llamado foo
si ambos tenían la misma firma y ambos eran hidebysig
- en C # la respuesta es no, pero si la respuesta es sí en VB entonces significa que la respuesta a esta pregunta es en realidad no determinista).
Bueno, no estoy seguro de cuánta ayuda es todo esto, aparte de ilustrar que en realidad es un problema mucho más difícil de lo que pensé (o me he perdido algo realmente obvio, en cuyo caso me gustaría saberlo). ) Pero, con suerte, tiene suficiente contenido que te ayuda a lograr lo que intentas hacer.