web-dev-qa-db-fra.com

C #: comment obtenir toutes les propriétés de chaîne publiques (à la fois get et set) d'un type

J'essaie de faire une méthode qui passera par une liste d'objets génériques et remplacera toutes leurs propriétés de type string qui est soit null soit vide avec un remplacement.

Comment est-ce une bonne façon de procéder?

J'ai ce genre de ... Shell ... jusqu'à présent:

public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
    var properties = typeof(T).GetProperties( -- What BindingFlags? -- );

    foreach(var p in properties)
    {
        foreach(var item in list)
        {
            if(string.IsNullOrEmpty((string) p.GetValue(item, null)))
                p.SetValue(item, replacement, null);
        }
    }
}

Alors, comment puis-je trouver toutes les propriétés d'un type qui sont:

  • De type string
  • A public get
  • A public set

    ?


J'ai fait cette classe de test:

class TestSubject
{
    public string Public;
    private string Private;

    public string PublicPublic { get; set; }
    public string PublicPrivate { get; private set; }
    public string PrivatePublic { private get; set; }
    private string PrivatePrivate { get; set; }
}

Ce qui suit ne fonctionne pas:

var properties = typeof(TestSubject)
        .GetProperties(BindingFlags.Instance|BindingFlags.Public)
        .Where(ø => ø.CanRead && ø.CanWrite)
        .Where(ø => ø.PropertyType == typeof(string));

Si j'imprime le nom des propriétés que j'y arrive, j'obtiens:

PublicPublic PublicPrivate PrivatePublic

En d'autres termes, j'obtiens trop deux propriétés.


Remarque : Cela pourrait probablement être fait d'une meilleure façon ... en utilisant imbriqué foreach et réflexion et tout ici ... mais si vous avez de bonnes idées alternatives, faites-le moi savoir car je veux apprendre!

54
Svish

Votre code réécrit. N'utilise pas LINQ ni var.

public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
    PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

    foreach (PropertyInfo p in properties)
    {
        // Only work with strings
        if (p.PropertyType != typeof(string)) { continue; }

        // If not writable then cannot null it; if not readable then cannot check it's value
        if (!p.CanWrite || !p.CanRead) { continue; }

        MethodInfo mget = p.GetGetMethod(false);
        MethodInfo mset = p.GetSetMethod(false);

        // Get and set methods have to be public
        if (mget == null) { continue; }
        if (mset == null) { continue; }

        foreach (T item in list)
        {
            if (string.IsNullOrEmpty((string)p.GetValue(item, null)))
            {
                p.SetValue(item, replacement, null);
            }
        }
    }
}
90
Colin Burnett

Vous trouverez les propriétés en tant que telles avec BindingFlags.Public | BindingFlags.Instance. Ensuite, vous devrez examiner chaque instance PropertyInfo en vérifiant les propriétés CanWrite et CanRead, afin de savoir si elles sont lisibles et/ou inscriptibles.

Mise à jour: exemple de code

PropertyInfo[] props = yourClassInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < props.Length; i++)
{
    if (props[i].PropertyType == typeof(string) && props[i].CanWrite)
    {
        // do your update
    }
}

Je l'ai approfondi après votre mise à jour. Si vous examinez également les objets MethodInfo renvoyés par GetGetMethod et GetSetMethod, vous atteindrez la cible, je pense;

 var properties = typeof(TestSubject).GetProperties(BindingFlags.Instance | BindingFlags.Public)
        .Where(ø => ø.CanRead && ø.CanWrite)
        .Where(ø => ø.PropertyType == typeof(string))
        .Where(ø => ø.GetGetMethod(true).IsPublic)
        .Where(ø => ø.GetSetMethod(true).IsPublic);

Par défaut, ces deux méthodes ne renvoient que des getters et setters publics (risquant une NullReferenceException dans un cas comme celui-ci), mais en passant true comme ci-dessus, elles retournent également des privées. Ensuite, vous pouvez examiner les propriétés IsPublic (ou IsPrivate).

9
Fredrik Mörk

Si vous ne spécifiez aucun indicateur de liaison, vous obtiendrez les propriétés d'instance publiques - c'est ce que vous voulez. Mais vous devrez ensuite vérifier si le PropertyType sur l'objet PropertyInfo est de type String. Sauf si vous le savez à l'avance, vous devrez également vérifier si la propriété est lisible/inscriptible comme l'indique @Fredrik.

using System.Linq;

public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
    var properties = typeof(T).GetProperties()
                              .Where( p => p.PropertyType == typeof(string) );
    foreach(var p in properties)
    {
        foreach(var item in list)
        {
            if(string.IsNullOrEmpty((string) p.GetValue(item, null)))
                p.SetValue(item, replacement, null);
        }
    }
}
1
tvanfosson

http://jefferytay.wordpress.com/2010/05/03/simple-and-useful-tostring/

pour une méthode de remplacement de chaîne qui vous permet d'obtenir toutes les propriétés de la classe

1
jeffery

Je suggère une approche différente: AOP .
Vous pouvez intercepter le programmateur et régler la valeur souhaitée sur une valeur valide. Avec PostSharp c'est assez simple.

0
Ron Klein

Je suis d'accord avec d'autres réponses, mais je préfère refactoriser la recherche elle-même pour être facilement interrogée avec Linq, de sorte que la requête pourrait être la suivante:

        var asm = Assembly.GetExecutingAssembly();
        var properties = (from prop
                              in asm.GetType()
                                .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                          where 
                            prop.PropertyType == typeof (string) && 
                            prop.CanWrite && 
                            prop.CanRead
                          select prop).ToList();
        properties.ForEach(p => Debug.WriteLine(p.Name));

J'ai pris pour exemple le type Assembly, qui n'a pas de propriétés de chaîne en lecture/écriture, mais si le même code recherche juste les propriétés en lecture, le résultat sera:

  • CodeBase
  • EscapedCodeBase
  • Nom complet
  • Emplacement
  • ImageRuntimeVersion

Quelles sont les chaînelecture seule Propriétés du type d'assemblage

0
Hoghweed

BindingFlags.Public | BindingFlags.Instance devrait le faire

GetSetMethod ()

0
ba__friend