Obtenir les propriétés et les valeurs d'un objet inconnu

150

Depuis le monde de PHP, j'ai décidé d'essayer C #. J'ai eu une recherche mais je n'arrive pas à trouver la réponse sur la façon de faire l'équivalent de cela.

$object = new Object();

$vars = get_class_vars(get_class($object));

foreach($vars as $var)
{
    doSomething($object->$var);
}

J'ai essentiellement une liste d'un objet. L'objet peut être l'un des trois types différents et aura un ensemble de propriétés publiques. Je veux pouvoir obtenir une liste des propriétés de l'objet, les parcourir en boucle et les écrire dans un fichier. Je pense que cela a quelque chose à voir avec la réflexion c # mais c'est tout nouveau pour moi.

Toute aide serait grandement appréciée.

m4rc
la source
9
En remarque: avoir des objets de types différents dans une liste (sans classe de base ou interface commune) n'est pas un bon style de programmation, du moins pas en c #.
Albin Sunnanbo

Réponses:

284

Cela devrait le faire:

Type myType = myObject.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());

foreach (PropertyInfo prop in props)
{
    object propValue = prop.GetValue(myObject, null);

    // Do something with propValue
}
Cocowalla
la source
d'où vient PropertyInfo?
Jonathan dos Santos
8
@jonathan System.Reflectionnamespace
Cocowalla
21
Il n'est pas vraiment nécessaire de créer une liste à partir d'un tableau, simplementPropertyInfo[] props = input.GetType().GetProperties();
VladL
2
Voulez-vous mettre à jour la réponse 2017 en utilisant Newtonsoft.Json.JsonConvert?
Vayne
1
@clone c'est une manière complètement différente de le faire. Vous devriez publier une réponse si vous pensez que c'est une approche valide
Cocowalla
23
void Test(){
    var obj = new{a="aaa", b="bbb"};

    var val_a = obj.GetValObjDy("a"); //="aaa"
    var val_b = obj.GetValObjDy("b"); //="bbb"
}
//create in a static class
static public object GetValObjDy(this object obj, string propertyName)
{            
     return obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}
Vo Van Khoa
la source
17

Oui, la réflexion serait la voie à suivre. Tout d'abord, vous obtiendrez le Typequi représente le type (au moment de l'exécution) de l'instance dans la liste. Vous pouvez le faire en appelant la GetTypeméthode surObject . Comme il se trouve sur la Objectclasse, il peut être appelé par chaque objet de .NET, car tous les types dérivent Object( enfin, techniquement, pas tout , mais ce n'est pas important ici).

Une fois que vous avez l' Typeinstance, vous pouvez appeler la GetPropertiesméthode pour obtenir les PropertyInfoinstances qui représentent les informations d'exécutiona sur les propriétés sur le Type.

Notez que vous pouvez utiliser les surcharges de GetPropertiespour classer qui propriétés que vous récupérez.

À partir de là, vous écririez simplement les informations dans un fichier.

Votre code ci-dessus, traduit, serait:

// The instance, it can be of any type.
object o = <some object>;

// Get the type.
Type type = o.GetType();

// Get all public instance properties.
// Use the override if you want to classify
// which properties to return.
foreach (PropertyInfo info in type.GetProperties())
{
    // Do something with the property info.
    DoSomething(info);
}

Notez que si vous voulez des informations de méthode ou des informations de champ, vous devrez appeler l'une des surcharges des méthodes GetMethodsou GetFieldsrespectivement.

Notez également que lister les membres d'un fichier est une chose, mais vous ne devez pas utiliser ces informations pour piloter la logique en fonction des ensembles de propriétés.

En supposant que vous ayez le contrôle sur les implémentations des types, vous devez dériver d'une classe de base commune ou implémenter une interface commune et faire les appels sur celles-ci (vous pouvez utiliser l' opérateur asou ispour déterminer avec quelle classe / interface de base vous travaillez) Durée).

Cependant, si vous ne contrôlez pas ces définitions de type et que vous devez piloter la logique en fonction de la correspondance de modèles, c'est très bien.

casperOne
la source
11

eh bien, en C #, c'est similaire. Voici l'un des exemples les plus simples (uniquement pour les propriétés publiques):

var someObject = new { .../*properties*/... };
var propertyInfos = someObject.GetType().GetProperties();
foreach (PropertyInfo pInfo in PropertyInfos)
{
    string propertyName = pInfo.Name; //gets the name of the property
    doSomething(pInfo.GetValue(someObject,null));
}
AlexanderMP
la source
9

Pour obtenir une valeur de propriété spécifique à partir du nom de propriété

public class Bike{
public string Name {get;set;}
}

Bike b = new Bike {Name = "MyBike"};

pour accéder à la valeur de propriété de Name à partir de la chaîne nom de propriété

public object GetPropertyValue(string propertyName)
{
//returns value of property Name
return this.GetType().GetProperty(propertyName).GetValue(this, null);
} 
Rajnikant
la source
3

Vous pouvez utiliser GetType - GetProperties - Linq Foreach :

obj.GetType().GetProperties().ToList().ForEach(p =>{
                                                        //p is each PropertyInfo
                                                        DoSomething(p);
                                                    });
Antonio DB
la source
3

Solution en une ligne utilisant Linq ...

var obj = new {Property1: 1, Property2: 2};
var property1 = obj.GetType().GetProperties().First(o => o.Name == "Property1").GetValue(obj , null);
Chris Wu
la source
2

Voici quelque chose que j'utilise pour transformer un IEnumerable<T>en un DataTablequi contient des colonnes représentant Tles propriétés de, avec une ligne pour chaque élément dans IEnumerable:

public static DataTable ToDataTable<T>(IEnumerable<T> items)
{
    var table = CreateDataTableForPropertiesOfType<T>();
    PropertyInfo[] piT = typeof(T).GetProperties();
    foreach (var item in items)
    {
        var dr = table.NewRow();
        for (int property = 0; property < table.Columns.Count; property++)
        {
            if (piT[property].CanRead)
            {
                var value = piT[property].GetValue(item, null);
                if (piT[property].PropertyType.IsGenericType)
                {
                    if (value == null)
                    {
                        dr[property] = DBNull.Value;
                    }
                    else
                    {
                        dr[property] = piT[property].GetValue(item, null);
                    }
                }
                else
                {
                    dr[property] = piT[property].GetValue(item, null);
                }
            }
        }
        table.Rows.Add(dr);
    }
    return table;
}

public static DataTable CreateDataTableForPropertiesOfType<T>()
{
    DataTable dt = new DataTable();
    PropertyInfo[] piT = typeof(T).GetProperties();
    foreach (PropertyInfo pi in piT)
    {
        Type propertyType = null;
        if (pi.PropertyType.IsGenericType)
        {
            propertyType = pi.PropertyType.GetGenericArguments()[0];
        }
        else
        {
            propertyType = pi.PropertyType;
        }
        DataColumn dc = new DataColumn(pi.Name, propertyType);

        if (pi.CanRead)
        {
            dt.Columns.Add(dc);
        }
    }
    return dt;
}

C'est "un peu" trop compliqué, mais c'est en fait assez bon pour voir quel est le résultat, comme vous pouvez lui donner un List<T>de, par exemple:

public class Car
{
    string Make { get; set; }
    int YearOfManufacture {get; set; }
}

Et vous recevrez un DataTable avec la structure:

Marque (chaîne)
YearOfManufacture (int)

Avec une ligne par élément dans votre List<Car>

Rob
la source
1

Cet exemple supprime toutes les propriétés de chaîne d'un objet.

public static void TrimModelProperties(Type type, object obj)
{
    var propertyInfoArray = type.GetProperties(
                                    BindingFlags.Public | 
                                    BindingFlags.Instance);
    foreach (var propertyInfo in propertyInfoArray)
    {
        var propValue = propertyInfo.GetValue(obj, null);
        if (propValue == null) 
            continue;
        if (propValue.GetType().Name == "String")
            propertyInfo.SetValue(
                             obj, 
                             ((string)propValue).Trim(), 
                             null);
    }
}
Brian Paske
la source
0

Je n'ai pas trouvé cela sur lequel travailler, disons les objets Application. J'ai cependant eu du succès avec

var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();

string rval = serializer.Serialize(myAppObj);
jcsubmit
la source
2
N'utilisez pas JavaScriptSerializer si vous pouvez l'éviter. Il y a de nombreuses raisons .
Nuno André
0
public Dictionary<string, string> ToDictionary(object obj)
{
    Dictionary<string, string> dictionary = new Dictionary<string, string>();

    Type objectType = obj.GetType();
    IList<PropertyInfo> props = new List<PropertyInfo>(objectType.GetProperties());

    foreach (PropertyInfo prop in props)
    {
        object propValue = prop.GetValue(obj, null);
        dictionary.Add(prop.Name, propValue.ToString());
    }

    return dictionary;
}
Ivan Porta
la source
0
    /// get set value field in object to object new (two object  field like ) 

    public static void SetValueObjectToObject (object sourceObj , object resultObj)
    {
        IList<PropertyInfo> props = new List<PropertyInfo>(sourceObj.GetType().GetProperties());
        foreach (PropertyInfo prop in props)
        {
            try
            {
                //get value in sourceObj
                object propValue = prop.GetValue(sourceObj, null);
                //set value in resultObj
                PropertyInfo propResult = resultObj.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
                if (propResult != null && propResult.CanWrite)
                {
                    propResult.SetValue(resultObj, propValue, null);
                }
            }
            catch (Exception ex)
            {  
                // do something with Ex
            }
        }
    }
namsdp
la source
-1

Vous pouvez essayer ceci:

string[] arr = ((IEnumerable)obj).Cast<object>()
                                 .Select(x => x.ToString())
                                 .ToArray();

Une fois que chaque tableau implémente l'interface IEnumerable

Pablo Rocha Villagra
la source