web-dev-qa-db-fra.com

c # - Comment parcourir les champs des classes et définir les propriétés

Je ne sais pas si cela est possible, mais je souhaite parcourir une classe et définir une propriété de membre de champ sans faire référence à l'objet champ explicitement:

public class Employee
{
  public Person _person = new Person();

  public void DynamicallySetPersonProperty()
  {
    MemberInfo[] members = this.GetType().GetMembers();

    foreach (MemberInfo member in members.Where(a => a.Name == "_person"))
    //get the _person field
    {

      Type type = member.GetType();
      PropertyInfo prop = type.GetProperty("Name"); //good, this works, now to set a value for it

      //this line does not work - the error is "property set method not found"
      prop.SetValue(member, "new name", null);
    }
  }
}


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

Dans la réponse que j'ai marquée comme réponse, vous devez ajouter:

  public static bool IsNullOrEmpty(this string source)
  {
    return (source == null || source.Length > 0) ? true : false;
  }
49
Petras
public class Person
{
    public string Name { get; set; }
}

public class Employee
{
    public Person person = new Person();

    public void DynamicallySetPersonProperty()
    {
        var p = GetType().GetField("person").GetValue(this);
        p.GetType().GetProperty("Name").SetValue(p, "new name", null);
    }
}
27

Voici un exemple de travail complet:

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

class Program
{
    static void PropertySet(object p, string propName, object value)
    {
        Type t = p.GetType();
        PropertyInfo info = t.GetProperty(propName);
        if (info == null)
            return;
        if (!info.CanWrite)
            return;
        info.SetValue(p, value, null);
    }

    static void PropertySetLooping(object p, string propName, object value)
    {
        Type t = p.GetType();
        foreach (PropertyInfo info in t.GetProperties())
        {
            if (info.Name == propName && info.CanWrite)
            {
                info.SetValue(p, value, null);
            }
        }
    }

    static void Main(string[] args)
    {
        Person p = new Person();

        PropertySet(p, "Name", "Michael Ellis");
        Console.WriteLine(p.Name);
        PropertySetLooping(p, "Name", "Nigel Mellish");
        Console.WriteLine(p.Name);
    }
}

EDIT: ajout d'une variante de bouclage pour que vous puissiez voir comment parcourir les objets d'informations de propriété.

31
plinth

Avec les méthodes d'extension suivantes que j'ai créées, vous pouvez définir ou obtenir n'importe quelle valeur de propriété même si elles sont imbriquées

GetPropertyValue (customObject, "Property.Nested.Child.Name");

ou définir

SetPropertyValue (customObject, "Property.Nested.Child.Name", "mon nom personnalisé");

        private class TargetProperty
    {
        public object Target { get; set; }
        public PropertyInfo Property { get; set; }

        public bool IsValid { get { return Target != null && Property != null; } }
    }

    private static TargetProperty GetTargetProperty(object source, string propertyName)
    {
        if (!propertyName.Contains("."))
            return new TargetProperty { Target = source, Property = source.GetType().GetProperty(propertyName) };

        string[] propertyPath = propertyName.Split('.');

        var targetProperty = new TargetProperty();

        targetProperty.Target = source;
        targetProperty.Property = source.GetType().GetProperty(propertyPath[0]);

        for (int propertyIndex = 1; propertyIndex < propertyPath.Length; propertyIndex++)
        {
            propertyName = propertyPath[propertyIndex];
            if (!string.IsNullOrEmpty(propertyName))
            {
                targetProperty.Target = targetProperty.Property.GetValue(targetProperty.Target, null);
                targetProperty.Property = targetProperty.Target.GetType().GetProperty(propertyName);
            }
        }

        return targetProperty;
    }


    public static bool HasProperty(this object source, string propertyName)
    {
        return GetTargetProperty(source, propertyName).Property != null;
    }

    public static object GetPropertyValue(this object source, string propertyName)
    {
        var targetProperty = GetTargetProperty(source, propertyName);
        if (targetProperty.IsValid)
        {
            return targetProperty.Property.GetValue(targetProperty.Target, null);
        }
        return null;
    }

    public static void SetPropertyValue(this object source, string propertyName, object value)
    {
        var targetProperty = GetTargetProperty(source, propertyName);
        if(targetProperty.IsValid)
        {
            targetProperty.Property.SetValue(targetProperty.Target, value, null);
        }
    }

Et voici quelques tests pour cela

    [TestFixture]
public class ObjectExtensionsTest
{

    private class MockClass
    {
        public MockClass()
        {
            Nested = new NestedMockClass();
        }

        public string Id { get; set; }
        public string Name { get; set; }

        public string GetOnly { get { return "MockClass"; } }
        public string SetOnly { set { } }

        public NestedMockClass Nested { get; set; }
    }

    private class NestedMockClass
    {
        public string NestedId { get; set; }
        public string NestedName { get; set; }

        public string NestedGetOnly { get { return "NestedMockClass"; } }
        public string NestedSetOnly { set { } }
    }

    [Test]
    public void TestShouldFindProperty()
    {
        MockClass mockObject = new MockClass();

        Assert.IsTrue(mockObject.HasProperty("Id"));
        Assert.IsTrue(mockObject.HasProperty("Name"));
        Assert.IsTrue(mockObject.HasProperty("GetOnly"));
        Assert.IsTrue(mockObject.HasProperty("SetOnly"));
        Assert.IsTrue(mockObject.HasProperty("Nested"));
        Assert.IsTrue(mockObject.HasProperty("Nested.NestedId"));
        Assert.IsTrue(mockObject.HasProperty("Nested.NestedName"));
        Assert.IsTrue(mockObject.HasProperty("Nested.NestedGetOnly"));
        Assert.IsTrue(mockObject.HasProperty("Nested.NestedSetOnly"));
    }

    [Test]
    public void TestShouldGetPropertyValue()
    {
        MockClass mockObject = new MockClass();

        mockObject.Id = "1";
        mockObject.Name = "Name";
        mockObject.Nested.NestedId = "NestedId";
        mockObject.Nested.NestedName = "NestedName";

        Assert.AreEqual(mockObject.Id, mockObject.GetPropertyValue("Id"));
        Assert.AreEqual(mockObject.Name, mockObject.GetPropertyValue("Name"));
        Assert.AreEqual(mockObject.GetOnly, mockObject.GetPropertyValue("GetOnly"));
        Assert.AreEqual(mockObject.Nested.NestedId, mockObject.GetPropertyValue("Nested.NestedId"));
        Assert.AreEqual(mockObject.Nested.NestedName, mockObject.GetPropertyValue("Nested.NestedName"));

    }

    [Test]
    public void TestShouldSetPropertyValue()
    {
        MockClass mockObject = new MockClass();

        mockObject.SetPropertyValue("Id", "1");
        mockObject.SetPropertyValue("Name", "Name");
        mockObject.SetPropertyValue("Nested.NestedId", "NestedId");
        mockObject.SetPropertyValue("Nested.NestedName", "NestedName");

        Assert.AreEqual(mockObject.Id, "1");
        Assert.AreEqual(mockObject.Name, "Name");
        Assert.AreEqual(mockObject.Nested.NestedId, "NestedId");
        Assert.AreEqual(mockObject.Nested.NestedName, "NestedName");

    }
}

J'espère que vous le trouverez utile.

10
Paleta

Vous essayez de définir la propriété Name du champ _person de votre classe Employee. Il n'en a pas. Essaye ça:

prop.SetValue(((FieldInfo)member).GetValue(this), "new name", null)

Je ne sais pas si vous devez lancer le premier argument comme ceci:

prop.SetValue((Person)((FieldInfo)member).GetValue(this), "new name", null)

Cela l'applique ensuite à la valeur du champ _person à la place.

5
David M

Vous essayez d'exécuter SetValue() sur la propriété Name de la variable member qui est un objet MemberInfo et cette propriété est en lecture seule.

Notez que vous n'avez pas besoin d'itérer sur tous les membres et que vous n'avez pas besoin d'obtenir le champ _person Avec réflexion car il est défini dans la même classe que la méthode DynamicallySetPersonProperty().

Le code doit donc se lire comme ceci.

PropertyInfo property = this._person.GetType().GetProperty("Name");

property.SetValue(this._person, "new name", null);

La première ligne échouera si _person Est nul. Vous pouvez donc utiliser reflectiopn pour obtenir le type de champ.

FieldInfo field = this.GetType().GetField("_person", BindingFlags.Public);

PropertyInfo property = field.FieldType.GetProperty("Name");

Mais maintenant, l'accès à cette propriété échouera toujours si _person Est nul.

property.Setvalue(field.GetValue(this), "new name", null);
4
Daniel Brückner

essaye ça:

public static void ApplyPropertyChanges(this object objDest, object objToCopyFrom)
    {
        if (objDest == null)
            throw new ArgumentNullException();
        if (objToCopyFrom == null)
            throw new ArgumentNullException("objToCopyFrom");
        if (objDest.GetType() != objToCopyFrom.GetType())
            throw new Exception("Invalid type. Required: \"" + objDest.GetType().ToString() + "\"");

        foreach (System.Reflection.PropertyInfo piOrig in objDest.GetType().GetProperties())
        {
            object editedVal = objToCopyFrom.GetType().GetProperty(piOrig.Name).GetValue(objToCopyFrom, null);

            piOrig.SetValue(objDest,
            editedVal,
            null);
        }
    }

exemple d'utilisation:

    public ActionResult Edit(Team editedTeamData)
    {
        if (!ModelState.IsValid)
            return View();

        Team origTeam = (from t in _db.Teams
                         where t.TeamID == editedTeamData.TeamID
                         select t).FirstOrDefault();

        origTeam.ApplyPropertyChanges(editedTeamData);
        _db.SubmitChanges();

        return RedirectToAction("Index");

    }
1
dev

Jetez un œil à cet article CodeProject lié à ce que vous essayez de faire

http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx

0
Chris Ballance