2009-04-06 9 views
49

मुझे यकीन है कि अगर यह संभव हो सकता है नहीं कर रहा हूँ सेट, लेकिन मैं क्षेत्र वस्तु स्पष्ट का जिक्र किए बिना एक वर्ग के माध्यम से पुनरावृति और एक क्षेत्र सदस्य संपत्ति सेट करना चाहते हैं:ग # - वर्गों क्षेत्रों के माध्यम से पुनरावृति कैसे और गुण

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; } 
} 

जवाब है कि मैं जवाब के रूप में चिह्नित में आप जोड़ने की जरूरत:

public static bool IsNullOrEmpty(this string source) 
    { 
    return (source == null || source.Length > 0) ? true : false; 
    } 
+0

यह विफल रहता है क्योंकि आपने memberinfo ऑब्जेक्ट पर संपत्ति का नाम सेट करने का प्रयास किया था। सदस्य की जानकारी का नाम है, लेकिन यह [_person] का नाम नहीं है। –

उत्तर

27
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); 
    } 
} 
+0

मुझे var p = person.GetType() जोड़ने की आवश्यकता है ... क्योंकि मैंने इसे एक अलग वर्ग – Petras

+2

से कॉल करना समाप्त कर दिया है यह काम नहीं करता है। यह 'GetField' के बजाय' GetProperty 'होना चाहिए था। – c00000fd

0

आप

करने के लिए कोशिश कर रहे हैं से संबंधित इस CodeProject लेख पर एक नज़र

4

आप अपने कर्मचारी वर्ग के _person फ़ील्ड की नाम संपत्ति सेट करने का प्रयास कर रहे हैं। इसमें कोई नहीं है। अगर आप इस तरह पहला तर्क कास्ट करने के लिए की जरूरत है

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

सुनिश्चित नहीं हैं: इस प्रयास करें

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

यह तो यह बजाय _person फ़ील्ड का मान लागू होता है।

+0

अभी भी एक ही त्रुटि प्राप्त करें, कम से कम मेरे कंप्यूटर पर। – Samuel

+0

संभवतः पहली तर्क डालने की आवश्यकता है? पोस्ट संपादित करेंगे। –

+0

तो क्या मैं, यह वही त्रुटि – Petras

4

आप एक चर member एक MemberInfo वस्तु है और इस proeprty केवल पढ़ने के लिए किया जाता है कि की संपत्ति Name पर SetValue() प्रदर्शन करने के लिए कोशिश कर रहा।

नोट करें कि आपको सभी memebers पर पुनरावृत्ति करने की आवश्यकता नहीं है और आपको _person फ़ील्ड को प्रतिबिंब के साथ प्राप्त करने की आवश्यकता नहीं है क्योंकि इसे विधि DynamicallySetPersonProperty() विधि के समान श्रेणी में परिभाषित किया गया है।

तो कोड इस तरह से पढ़ा गया है।

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

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

_person शून्य होने पर पहली पंक्ति विफल हो जाएगी। तो आप फ़ील्ड के प्रकार को पाने के लिए परावर्तक का उपयोग कर सकते हैं।

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

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

लेकिन अब अभी भी विफल हो जाएगा यदि _person रिक्त है इस संपत्ति तक पहुँचने।

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); 
    } 
} 

संपादित करें:

property.Setvalue(field.GetValue(this), "new name", null); 
30

यहां एक संपूर्ण काम कर उदाहरण है एक पाशन संस्करण जोड़ा ताकि आप देख सकते हैं कि कैसे संपत्ति की जानकारी वस्तुओं लूप करने के लिए।

+1

इसे उत्तर के रूप में चिह्नित किया जाना चाहिए था। – c00000fd

10
निम्नलिखित एक्सटेंशन तरीकों कि मैं पैदा की है, तो आप सेट या भले ही वे

GetPropertyValue (customObject, "Property.Nested.Child.Name") नेस्टेड रहते हैं किसी भी संपत्ति के मूल्य प्राप्त कर सकते हैं के साथ

;

या सेट

SetPropertyValue (customObject, "Property.Nested.Child।। नाम "," मेरी मनपसंद नाम ");

 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); 
     } 
    } 

और यहाँ के लिए यह

[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"); 

    } 
} 

आशा है कि आप इसे उपयोगी पाते

+0

उत्कृष्ट, यह – Petras

+0

काम करता है यदि यह काम करता है, तो कृपया इसे सही उत्तर के रूप में जोड़ें: डी – Paleta

+0

बहुत अच्छा ... विशेष रूप से घोंसले के साथ। प्लिंथ का उदाहरण सरल है, लेकिन इसमें कोई घोंसला नहीं है। इसके अलावा, यहां किसी और के लिए लैंडिंग करने के लिए (मुझे पसंद है) यह समझने के लिए चारों ओर खोदना था कि बिल्ली "एक्सटेंशन" क्या था, यह एक अच्छा और संक्षिप्त स्पष्टीकरण है: http://msdn.microsoft.com/en-us/library/ bb311042.aspx – Russ

1

परीक्षण के एक जोड़े हैं इस प्रयास करें:

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); 
     } 
    } 

उपयोग उदाहरण:

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"); 

    } 
संबंधित मुद्दे