Cómo obtener una propiedad estática con Reflection

109

Así que esto parece bastante básico, pero no puedo hacerlo funcionar. Tengo un objeto y estoy usando la reflexión para llegar a sus propiedades públicas. Una de estas propiedades es estática y no tengo suerte para acceder a ella.

Public Function GetProp(ByRef obj As Object, ByVal propName as String) as PropertyInfo
    Return obj.GetType.GetProperty(propName)

End Function

El código anterior funciona bien para las propiedades de instancia pública, que hasta ahora es todo lo que necesitaba. Supuestamente puedo usar BindingFlags para solicitar otros tipos de propiedades (privadas, estáticas), pero parece que no puedo encontrar la combinación correcta.

Public Function GetProp(ByRef obj As Object, ByVal propName as String) as PropertyInfo
    Return obj.GetType.GetProperty(propName, Reflection.BindingFlags.Static Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)

End Function

Pero aún así, solicitar que cualquier miembro de Static no devuelva nada. El reflector .NET puede ver las propiedades estáticas muy bien, así que claramente me falta algo aquí.

Corey Downie
fuente
Esto es muy, muy similar a esto: stackoverflow.com/questions/392122/…
ctacke
Bueno, es similar en que ambos usan BindingFlags. Estoy buscando una combinación específica de BindingFlags que me permita obtener miembros públicos, ya sean estáticos o de instancia.
Corey Downie

Respuestas:

129

O simplemente mira esto ...

Type type = typeof(MyClass); // MyClass is static class with static properties
foreach (var p in type.GetProperties())
{
   var v = p.GetValue(null, null); // static classes cannot be instanced, so use null...
}
Ernesto
fuente
2
¿A qué variables corresponden estos dos nulos? ¿Cómo escribirías esto usando argumentos con nombre, si es posible? Gracias.
Hamish Grubijan
¿Para clase estática interna?
Kiquenet
Esta es la mejor opción, en mi opinión debería seleccionarse como respuesta.
c0y0teX
8
p.GetValue(null);también funciona. El segundo nullno es obligatorio.
Chrono
Se ve muy bien. El objetivo era obtener la propiedad en función de un argumento de nombre; no creo que quisiera recorrer todas las propiedades para lograrlo.
Corey Downie
42

Esto es C #, pero debería darte la idea:

public static void Main() {
    typeof(Program).GetProperty("GetMe", BindingFlags.NonPublic | BindingFlags.Static);
}

private static int GetMe {
    get { return 0; }
}

(necesita OR NonPublic y Static solamente)

EarnNameless
fuente
3
En mi caso, usar solo estas dos banderas no funcionó. También tuve que usar la bandera .FlattenHierarchy.
Corey Downie
3
@CoreyDownie estuvo de acuerdo. BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchyfue lo único que funcionó para mí.
Jonathon Reinhart
40

Un poco de claridad ...

// Get a PropertyInfo of specific property type(T).GetProperty(....)
PropertyInfo propertyInfo;
propertyInfo = typeof(TypeWithTheStaticProperty)
    .GetProperty("NameOfStaticProperty", BindingFlags.Public | BindingFlags.Static); 

// Use the PropertyInfo to retrieve the value from the type by not passing in an instance
object value = propertyInfo.GetValue(null, null);

// Cast the value to the desired type
ExpectedType typedValue = (ExpectedType) value;
Jorge
fuente
1
BindingFlags.Instance | BindingFlags.Staticme lo resolvió.
LosManos
28

Ok, entonces la clave para mí fue usar .FlattenHierarchy BindingFlag. Realmente no sé por qué lo agregué por una corazonada y comenzó a funcionar. Entonces, la solución final que me permite obtener Instancia pública o Propiedades estáticas es:

obj.GetType.GetProperty(propName, Reflection.BindingFlags.Public _
  Or Reflection.BindingFlags.Static Or Reflection.BindingFlags.Instance Or _
  Reflection.BindingFlags.FlattenHierarchy)
Corey Downie
fuente
7
myType.GetProperties(BindingFlags.Public | BindingFlags.Static |  BindingFlags.FlattenHierarchy);

Esto devolverá todas las propiedades estáticas en la clase base estática o un tipo en particular y probablemente también el hijo.

Igor
fuente
2

Solo quería aclarar esto por mí mismo, mientras utilizo la nueva API de reflexión basada en TypeInfo- donde BindingFlagsno está disponible de manera confiable (según el marco de trabajo de destino).

En la reflexión 'nueva', para obtener las propiedades estáticas de un tipo (sin incluir las clases base), debe hacer algo como:

IEnumerable<PropertyInfo> props = 
  type.GetTypeInfo().DeclaredProperties.Where(p => 
    (p.GetMethod != null && p.GetMethod.IsStatic) ||
    (p.SetMethod != null && p.SetMethod.IsStatic));

Se adapta tanto a propiedades de solo lectura como de solo escritura (a pesar de que solo escritura es una idea terrible).

El DeclaredPropertiesmiembro tampoco distingue entre propiedades con descriptores de acceso públicos / privados; por lo tanto, para filtrar la visibilidad, debe hacerlo en función del descriptor de acceso que necesite utilizar. Por ejemplo, suponiendo que la llamada anterior haya regresado, podría hacer:

var publicStaticReadable = props.Where(p => p.GetMethod != null && p.GetMethod.IsPublic);

Hay algunos métodos de acceso directo disponibles, pero en última instancia, todos escribiremos muchos más métodos de extensión en torno a los TypeInfométodos / propiedades de consulta en el futuro. Además, la nueva API nos obliga a pensar exactamente en lo que consideramos una propiedad 'privada' o 'pública' a partir de ahora, porque debemos filtrarnos en función de los accesos individuales.

Andras Zoltan
fuente
1

Lo siguiente parece funcionar para mí.

using System;
using System.Reflection;

public class ReflectStatic
{
    private static int SomeNumber {get; set;}
    public static object SomeReference {get; set;}
    static ReflectStatic()
    {
        SomeReference = new object();
        Console.WriteLine(SomeReference.GetHashCode());
    }
}

public class Program
{
    public static void Main()
    {
        var rs = new ReflectStatic();
        var pi = rs.GetType().GetProperty("SomeReference",  BindingFlags.Static | BindingFlags.Public);
        if(pi == null) { Console.WriteLine("Null!"); Environment.Exit(0);}
        Console.WriteLine(pi.GetValue(rs, null).GetHashCode());


    }
}
Vyas Bharghava
fuente
-3

Prueba esta reflexión de C # enlace de .

Tenga en cuenta que creo que BindingFlags.Instance y BindingFlags.Static son exclusivos.

Ken Henderson
fuente
Sí, espero que ese no sea el caso, porque lo que quiero es poder obtener cualquier instancia pública o estática.
Corey Downie
No son exclusivos. Lo acabo de probar.
LosManos