Comment obtenir une propriété statique avec Reflection

109

Cela semble donc assez basique mais je ne peux pas le faire fonctionner. J'ai un objet et j'utilise la réflexion pour accéder à ses propriétés publiques. L'une de ces propriétés est statique et je n'ai pas de chance d'y arriver.

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

End Function

Le code ci-dessus fonctionne très bien pour les propriétés d'instance publique, ce qui jusqu'à présent est tout ce dont j'avais besoin. On suppose que je peux utiliser BindingFlags pour demander d'autres types de propriétés (privées, statiques), mais je n'arrive pas à trouver la bonne combinaison.

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

Mais quand même, demander à des membres statiques ne renvoie rien. Le réflecteur .NET peut voir les propriétés statiques très bien, donc il me manque clairement quelque chose ici.

Corey Downie
la source
C'est vraiment, vraiment similaire à ceci: stackoverflow.com/questions/392122/…
ctacke
Eh bien, c'est similaire en ce sens qu'ils utilisent tous les deux BindingFlags. Je recherche une combinaison spécifique de BindingFlags qui me permettra d'obtenir des membres publics, qu'ils soient statiques ou d'instance.
Corey Downie

Réponses:

129

Ou regardez simplement ceci ...

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...
}
Ernest
la source
2
À quelles variables correspondent ces deux valeurs nulles? Comment écririez-vous cela en utilisant des arguments nommés, si c'est possible? Merci.
Hamish Grubijan
Pour la classe statique interne?
Kiquenet
C'est la meilleure option, à mon avis, elle devrait être choisie comme réponse.
c0y0teX
8
p.GetValue(null);fonctionne aussi. Le second nulln'est pas obligatoire.
Chrono
Ça a l'air génial. Le but était d'obtenir la propriété sur la base d'un argument de nom - je ne pense pas que je voudrais faire une boucle sur une propriété pour y parvenir.
Corey Downie
42

Ceci est C #, mais devrait vous donner l'idée:

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

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

(vous devez OU non public et statique uniquement)

comte
la source
3
Dans mon cas, n'utiliser que ces deux indicateurs ne fonctionnait pas. J'ai dû également utiliser l'indicateur .FlattenHierarchy.
Corey Downie
3
@CoreyDownie était d'accord. BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchyétait la seule chose qui fonctionnait pour moi.
Jonathon Reinhart
40

Un peu de clarté ...

// 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;
George
la source
1
BindingFlags.Instance | BindingFlags.Staticrésolu pour moi.
LosManos
28

Ok donc la clé pour moi était d'utiliser le .FlattenHierarchy BindingFlag. Je ne sais pas vraiment pourquoi je l'ai simplement ajouté par intuition et que cela a commencé à fonctionner. Donc, la solution finale qui me permet d'obtenir une instance publique ou des propriétés statiques est:

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

Cela retournera toutes les propriétés statiques dans la classe de base statique ou un type particulier et probablement aussi l'enfant.

Igor
la source
2

Je voulais juste clarifier cela pour moi-même, tout en utilisant la nouvelle API de réflexion basée sur TypeInfo- où BindingFlagsn'est pas disponible de manière fiable (en fonction du cadre cible).

Dans la `` nouvelle '' réflexion, pour obtenir les propriétés statiques d'un type (sans inclure les classes de base), vous devez faire quelque chose comme:

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

Convient à la fois aux propriétés en lecture seule ou en écriture seule (bien que l'écriture seule soit une mauvaise idée).

Le DeclaredPropertiesmembre ne fait pas non plus la distinction entre les propriétés avec des accesseurs publics / privés - donc pour filtrer autour de la visibilité, vous devez ensuite le faire en fonction de l'accesseur que vous devez utiliser. Par exemple, en supposant que l'appel ci-dessus est retourné, vous pouvez faire:

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

Il existe des méthodes de raccourci disponibles - mais en fin de compte, nous allons tous écrire beaucoup plus de méthodes d'extension autour des TypeInfométhodes / propriétés de requête à l'avenir. De plus, la nouvelle API nous oblige à réfléchir à ce que nous considérons désormais comme une propriété «privée» ou «publique», car nous devons nous filtrer en fonction des accesseurs individuels.

Andras Zoltan
la source
1

Le ci-dessous semble fonctionner pour moi.

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
la source
-3

Essayez ce lien de réflexion C # .

Notez que je pense que BindingFlags.Instance et BindingFlags.Static sont exclusifs.

Ken Henderson
la source
Ouais, j'espère que ce n'est pas le cas, car ce que je veux, c'est pouvoir obtenir une instance publique ou statique.
Corey Downie
Ils ne sont pas exclusifs. Je viens de le tester.
LosManos