2009-07-30 14 views
35

जब मैं प्रतिबिंब तंत्र के माध्यम से इसमें हूं तो मैं संपत्ति का नाम प्राप्त करना चाहता हूं। क्या यह संभव है?प्रतिबिंब के माध्यम से वर्तमान संपत्ति का नाम कैसे प्राप्त करें?

अद्यतन: मैं इस तरह कोड है:

public CarType Car 
    { 
     get { return (Wheel) this["Wheel"];} 
     set { this["Wheel"] = value; } 
    } 

और मैं कुछ इस तरह करना चाहते हैं क्योंकि मैं इस तरह के और अधिक गुण की जरूरत है:

public CarType Car 
    { 
     get { return (Wheel) this[GetThisPropertyName()];} 
     set { this[GetThisPropertyName()] = value; } 
    } 
+1

+1 मैं भी इस बारे में सोचा जब System.Configuration.ApplicationSettingsBase –

उत्तर

47

के बाद से गुण वास्तव में सिर्फ तरीकों आप ऐसा करते हैं और get_ साफ कर सकते हैं कर रहे हैं दिखाई:

class Program 
    { 
     static void Main(string[] args) 
     { 
      Program p = new Program(); 
      var x = p.Something; 
      Console.ReadLine(); 
     } 

     public string Something 
     { 
      get 
      { 
       return MethodBase.GetCurrentMethod().Name; 
      } 
     } 
    } 

आप प्रदर्शन प्रोफ़ाइल यदि आप MethodBase.GetCurrentMethod() खोजना चाहिए मील StackFrame की तुलना में तेजी है। .NET 1.1 में आपको रिलीज मोड में स्टैकफ्रेम के साथ भी समस्याएं होंगी (स्मृति से मुझे लगता है कि मुझे लगता है कि यह 3x तेज था)।

यह कहा गया कि मुझे यकीन है कि प्रदर्शन समस्या बहुत अधिक समस्या का कारण नहीं बनती है- हालांकि स्टैकफ्रेम स्लोनेस पर एक रोचक चर्चा found here हो सकती है।

मुझे लगता है कि यदि आप प्रदर्शन के बारे में चिंतित हैं तो एक और विकल्प एक विजुअल स्टूडियो इंटेलिसेंस कोड स्निपेट बनाना होगा जो आपके लिए संपत्ति बनाता है और एक स्ट्रिंग भी बनाता है जो संपत्ति के नाम से मेल खाता है।

[CrmAttribute("firstname")] 
    public string FirstName 
    { 
     get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); } 
     set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); } 
    } 

    // this is in a base class, skipped that bit for clairty 
    public T GetPropValue<T>(string propName) 
    { 
     propName = propName.Replace("get_", "").Replace("set_", ""); 
     string attributeName = GetCrmAttributeName(propName); 
     return GetAttributeValue<T>(attributeName);    
    } 

    public void SetPropValue(string propName, object value) 
    { 
     propName = propName.Replace("get_", "").Replace("set_", ""); 
     string attributeName = GetCrmAttributeName(propName); 
     SetAttributeValue(attributeName, value); 
    } 

    private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>(); 
    private string GetCrmAttributeName(string propertyName) 
    { 
     // keyName for our propertyName to (static) CrmAttributeName cache 
     string keyName = this.GetType().Name + propertyName; 
     // have we already done this mapping? 
     if (!PropToAttributeMap.ContainsKey(keyName)) 
     { 
      Type t = this.GetType(); 
      PropertyInfo info = t.GetProperty(propertyName); 
      if (info == null) 
      { 
       throw new Exception("Cannot find a propety called " + propertyName); 
      } 

      object[] attrs = info.GetCustomAttributes(false); 
      foreach (object o in attrs) 
      { 
       CrmAttributeAttribute attr = o as CrmAttributeAttribute ; 
       if (attr != null) 
       { 
        // found it. Save the mapping for next time. 
        PropToAttributeMap[keyName] = attr.AttributeName; 
        return attr.AttributeName; 
       } 
       } 
       throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value"); 
      } 

      // return the existing mapping 
      string result = PropToAttributeMap[keyName]; 
      return result; 
     } 

वहाँ एक कस्टम विशेषता वर्ग CrmAttributeAttribute बुलाया भी है:

+0

दिलचस्प - मुझे GetCurrentMethod() – BlueMonkMN

+0

के बारे में पता नहीं था क्या आप 'Properties' के लिए ऐसा कुछ करते हैं? –

0

हाँ, यह है!

string test = "test string"; 
Type type = test.GetType(); 

PropertyInfo[] propInfos = type.GetProperties(); 
for (int i = 0; i < propInfos.Length; i++) 
{ 
    PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i); 
    string propName = pi.Name; 
} 
0

कॉल स्टैक पर प्रतिबिंबित करने के लिए System.Diagnostics.StackTrace का उपयोग करने का प्रयास करें। संपत्ति कॉल स्टैक में कहीं कहीं होनी चाहिए (शायद शीर्ष पर यदि आप इसे सीधे संपत्ति के कोड से कॉल कर रहे हैं)।

5

इसके बजाय MethodBase.GetCurrentMethod() का उपयोग करें!

प्रतिबिंब का उपयोग ऐसे प्रकारों के साथ करने के लिए किया जाता है जो संकलन समय पर नहीं किए जा सकते हैं। उस संपत्ति एक्सेसर का नाम प्राप्त करने पर आप संकलित समय पर निर्णय ले सकते हैं ताकि आपको इसके लिए प्रतिबिंब का उपयोग न करना पड़े।

हालांकि आप System.Diagnostics.StackTrace का उपयोग कर कॉल स्टैक से एक्सेसर विधि का नाम उपयोग करते हैं।

string GetPropertyName() 
    { 
     StackTrace callStackTrace = new StackTrace(); 
     StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame 
     string properyAccessorName = propertyFrame.GetMethod().Name; 

     return properyAccessorName.Replace("get_","").Replace("set_",""); 
    } 
+1

को लागू करने मैं इस तरह बातें कर रहे हैं और यह मुझे वापस पकड़ लिया। सावधान रहें यदि संपत्ति को रेखांकित किया गया है: गेटटर/सेटर की मदद करने से पहले [MethodImpl (MethodImplOptions.NoInlining)] डालने से पहले, लेकिन यह असुविधाजनक है ... –

6

मैं संदर्भ में आपको इसकी आवश्यकता के बाद से मुझे लगता है आप पहले से ही पता होना चाहिए कि क्या संपत्ति आप संपत्ति एक्सेसर में साथ काम कर रहे के बारे में अधिक जानना चाहते हैं। यदि आपको, हालांकि, आप शायद MethodBase.GetCurrentMethod() का उपयोग कर सकते हैं। get_/set_ के बाद कुछ भी हटा दें।

अद्यतन:

अपने परिवर्तनों के आधार पर, मैं कहूँगा कि आप प्रतिबिंब के बजाय विरासत का उपयोग करना चाहिए। मुझे नहीं पता कि आपके शब्दकोश में कौन सा डेटा है, लेकिन ऐसा लगता है कि आप वास्तव में अलग-अलग कार कक्षाएं चाहते हैं, सेडान, रोडस्टर, बग्गी, स्टेशन वैगन कहते हैं, इस प्रकार को स्थानीय चर में नहीं रखते हैं। फिर आपके पास उन तरीकों के कार्यान्वयन होंगे जो उस प्रकार की कार के लिए उचित चीज करते हैं। आपके पास किस तरह की कार है, यह जानने के बजाय, कुछ करने के बाद, आप बस उचित विधि को कॉल करें और कार ऑब्जेक्ट सही प्रकार की चीज़ों के आधार पर सही चीज़ करता है।

public interface ICar 
{ 
     void Drive(decimal velocity, Orientation orientation); 
     void Shift(int gear); 
     ... 
} 

public abstract class Car : ICar 
{ 
     public virtual void Drive(decimal velocity, Orientation orientation) 
     { 
      ...some default implementation... 
     } 

     public abstract void Shift(int gear); 

     ... 
} 

public class AutomaticTransmission : Car 
{ 
     public override void Shift(int gear) 
     { 
      ...some specific implementation... 
     } 
} 

public class ManualTransmission : Car 
{ 
     public override void Shift(int gear) 
     { 
      ...some specific implementation... 
     } 
} 
+0

अधिक उदाहरण: http://www.codeproject.com /KB/dotnet/MethodName.aspx –

+0

मैंने अपने संदर्भ के बारे में कुछ और स्पष्टीकरण जोड़ा है। –

+0

आपके अपडेट सिर्फ दिखाएं कि आपको इसके लिए प्रतिबिंब का उपयोग क्यों नहीं करना चाहिए। सुझाए गए प्रतिबिंब के तरीके का उपयोग करके, आप शायद यह पता लगाना चाहते हैं कि आप "GetThisPropertyName" के अंदर हैं, और आपको "यह प्रॉपर्टी नाम" संपत्ति का निर्णय लेने का निर्णय लेते हैं। वास्तविक संपत्ति कॉल प्राप्त करने के लिए आपको एक स्टैक कॉल "डाउन" जाने के लिए उदाहरण को ट्विक करना होगा। हालांकि यह संभव है, यह एक ओवरकिल की तरह दिखता है। आपका कोड इस [GetThisPropertyName()] कॉल की कॉपी/पेस्ट के साथ छिड़का जाएगा, और यह और अधिक पठनीय (IMHO) नहीं होगा। मैं व्यक्तिगत रूप से सामान्य स्ट्रिंग dict accessor का उपयोग करना चाहता हूं। –

3

FWIW मैं इस तरह एक प्रणाली लागू की।

मैं दृढ़ता से के खिलाफ अपने समाधान के हिस्से के रूप GetStackFrame() का उपयोग की सलाह देते हैं, समाधान के अपने मूल संस्करण मूल रूप से बहुत neater था:

return GetPropValue<string>(); 

लेकिन यह ऊपर संस्करण की तुलना में धीमी थी 600x ।

3

थोड़ा सा भ्रमित उदाहरण जो आपने प्रस्तुत किया, जब तक कि मुझे यह नहीं मिलता है। सी # 6.0 से आप nameof ऑपरेटर का उपयोग कर सकते हैं।

public CarType MyProperty 
{ 
    get { return (CarType)this[nameof(MyProperty)]}; 
    set { this[nameof(MyProperty)] = value]}; 
} 

आप एक विधि है कि आपके गेटर/सेटर वैसे भी संभालती है, तो आप सी # 4.5 CallerMemberName विशेषता का उपयोग कर सकते हैं, इस मामले में तुम भी नाम दोहराने की जरूरत नहीं है।

public CarType MyProperty 
{ 
    get { return Get<CarType>(); } 
    set { Set(value); } 
} 

public T Get<T>([CallerMemberName]string name = null) 
{ 
    return (T)this[name]; 
} 

public void Set<T>(T value, [CallerMemberName]string name = null) 
{ 
    this[name] = value; 
} 
+0

मैं हर बार 'nameof' के जादू के बारे में भूल जाता रहता हूं। मैंने देखा कि अन्य सभी समाधानों के अलावा 'नाम (संपत्ति)' को कॉल करना बहुत आसान है। यह पुष्टि करते हुए कि 'nameof (item.PropertyName)' बस मेरे लिए एक आकर्षण की तरह काम किया। हालांकि यह उनकी स्थिति के आधार पर दूसरों के लिए भिन्न हो सकता है। – Niklas

+1

@ निकलास 'nameof' सी # के साथ पेश किए गए सबसे महान वाक्यविन्यास सुधारों में से एक है। लगभग अप्रचलित कोड में शाब्दिक तारों का उपयोग करके बनाता है, इस प्रकार न केवल सुविधा में सुधार बल्कि कोड सुरक्षा भी बनाता है। मैं इसका हर समय उपयोग करता हूं। –

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

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