2009-07-14 9 views
10

यह किसी संपत्ति के नाम को बदलने के लिए कुछ आम घटना होनी चाहिए और उम्मीदवारों को संपत्ति के संपत्ति नाम को छोड़कर, सभी आवश्यक नामांकन का ख्याल रखने के लिए विजुअल स्टूडियो में नाम बदलने की अपेक्षा करना चाहिए, INOTifyPropertyChanged की संपत्ति बदलें। क्या किसी भी तरह से इसे दृढ़ता से टाइप करने का कोई बेहतर तरीका है, इसलिए आपको इसे मैन्युअल रूप से नाम बदलने के लिए याद रखने की आवश्यकता नहीं है?क्या सी # में PropertyChanged घटनाओं को करने के लिए कोई दृढ़ता से टाइप किया गया तरीका है?

+0

(उदाहरण/टिप्पणी के अनुसार जोड़ा गया उदाहरण) –

+1

इस आलेख पर एक नज़र डालें। http://weblogs.asp.net/dwahlin/archive/2009/07/07/validating-properties-in-silverlight-classes.aspx यदि आप एक बेस क्लास बनाते हैं जो INotifyProperty को लागू करता है और फिर उससे प्राप्त होता है, शायद आप इसका इस्तेमाल कर सकते हैं। –

+1

http://stackoverflow.com/questions/1329138/how-to-make-databinding-type-safe-and-support-refactoring/1333874#1333874 इनोटिलीप्रॉपर्टी को लागू करने के एक कंपाइलर चेक किए गए तरीके के लिए देखें। एक जादू स्ट्रिंग के रूप में संपत्ति के नाम होने से बचें। –

उत्तर

8

संपादित करें: nameof सी # 6. में पहुंचे!


कोई nameof/infoof आदि नहीं है; यह बहुत चर्चा की गई है, लेकिन यह वही है।

.NET 3.5 (और अभिव्यक्ति वृक्ष को पार्सिंग) में लैम्ब्डा अभिव्यक्तियों का उपयोग करने का एक तरीका है, लेकिन वास्तव में यह ओवरहेड के लायक नहीं है। अभी के लिए, मैं सिर्फ स्ट्रिंग्स (और इकाई परीक्षणों के साथ चिपकना चाहूंगा यदि आप इसे तोड़ने के लिए निर्धारित नहीं हैं)।


using System; 
using System.ComponentModel; 
using System.Linq.Expressions; 
using System.Reflection; 
class Program : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged; 
    static void Main() { 
     var p = new Program(); 
     p.PropertyChanged += (s, a) => Console.WriteLine(a.PropertyName); 
     p.Name = "abc"; 
    } 
    protected void OnPropertyChanged<T>(Expression<Func<Program, T>> property) { 
     MemberExpression me = property.Body as MemberExpression; 
     if (me == null || me.Expression != property.Parameters[0] 
       || me.Member.MemberType != MemberTypes.Property) { 
      throw new InvalidOperationException(
       "Now tell me about the property"); 
     } 
     var handler = PropertyChanged; 
     if (handler != null) handler(this, 
      new PropertyChangedEventArgs(me.Member.Name)); 
    } 
    string name; 
    public string Name { 
     get{return name;} 
     set { 
      name = value; 
      OnPropertyChanged(p=>p.Name); 
     } 
    } 
} 
+0

मैं शायद तारों से चिपक जाऊंगा, लेकिन किक्स के लिए, क्या आप अभिव्यक्ति वृक्ष को पार्स करने के तरीके पर एक संक्षिप्त कोड नमूना दे सकते हैं? – Davy8

+0

'अभिव्यक्ति > 'और'() => नाम' के बजाय आप' अभिव्यक्ति > 'और' p => p.Name' का उपयोग क्यों करते हैं? – Svish

+1

या तो ठीक होगा, लेकिन पोस्ट के रूप में संस्करण यह स्पष्ट करता है कि हम उदाहरण पर एक संपत्ति की तलाश में हैं - न केवल कुछ यादृच्छिक। –

0

आपके प्रश्न का उत्तर नहीं है, लेकिन यदि आप राइट-क्लिक-> रिएक्टर-> किसी संपत्ति का नाम बदलते हैं, तो यह मेलिंग तारों का नाम बदल सकता है, जिसमें आपकी संपत्ति के नाम से मेल खाने वाले किसी भी स्ट्रिंग शामिल हैं।

हाँ, यह थोड़ा खतरनाक हो सकता है।

+0

यहां तक ​​कि टिप्पणियों में नाम बदलना खतरनाक है। मैंने यह मानकर एक बड़ी परियोजना में एक्सएमएल दस्तावेज का एक गुच्छा गड़बड़ कर दिया कि यह सुविधा कोड तत्व के नाम पर टिप्पणियों के दायरे को सीमित कर देगी। – snarf

-1

PropertyChangedEventArgs केवल एक कन्स्ट्रक्टर लेता है, जिसके लिए संपत्ति का नाम स्ट्रिंग के रूप में आवश्यक होता है। इसलिए अनिवार्य रूप से कोई भी उपयोग नहीं किया जा रहा है IotifyPropertyChanged का अर्थ है कि कुछ स्तर पर, यह आपके आर्किटेक्चर में उच्च या निम्न हो, आपको एक स्ट्रिंग और मैन्युअल नामकरण के साथ काम करना होगा।

2

सरल समाधान स्टैक ट्रेस को देखो और पूरी तरह से संपत्ति के लिए हर स्पष्ट संदर्भ दूर करने के लिए है। संपत्ति सेटर set_<PropertyName> नामित विधि है कि -

public String Name 
{ 
    get { return this.name; } 
    set 
    { 
     if (value != this.name) 
     { 
      this.RaisePropertyChanging(); 
      this.name = value; 
      this.RaisePropertyChanged(); 
     } 
    } 
} 
private String name = null; 

private void RaisePropertyChanged() 
{ 
    String propertyName = 
     new StackTrace().GetFrame(1).GetMethod().Name.SubString(4); 

    PropertyChangedEventHandler handler = this.PropertyChanged; 
    if (handler != null) 
    { 
     handler(new PropertyChangedEventArgs(propertyName)); 
    } 
} 

कोड caling विधि से स्टैक ट्रेस के माध्यम से संपत्ति नाम निकला। यदि संकलक अब इस नामकरण सम्मेलन का पालन नहीं करता है, तो कोड टूट जाता है।

दूसरा समाधान संपत्ति नाम को लैम्ब्डा अभिव्यक्ति से प्राप्त करना है।

public static String GetPropertyNameFromLambdaExpression<TObject, TProperty>(
    Expression<Func<TObject, TProperty>> expression) 
{ 
    return ((MemberExpression)expression.Body).Member.Name; 
} 

उदाहरण

GetPropertyNameFromLambdaExpression<String, Int32>(s => s.Length) 

के लिए "Length" के रूप में exspected वापस आ जाएगी। कोड का एक उत्पादन संस्करण वास्तव में अतिरिक्त कोड और शेष कोड में बेहतर एकीकरण की मांग करता है। उदाहरण के लिए सामान्य तर्कों के लिए प्रकार अनुमान का उपयोग करना संभव है।

अद्यतन

और वहाँ एक तिहाई समाधान है - आप सेटर या गेटर विधि का नाम प्राप्त करने के लिए एक संपत्ति गेटर या सेटर अंदर MethodBase.GetCurrentMethod() उपयोग कर सकते हैं।

public String Name 
{ 
    get { return this.name; } 
    set 
    { 
     if (value != this.name) 
     { 
      String propertyName = MethodBase.GetCurentMethod().Name.SubString(4); 

      this.RaisePropertyChanging(propertyName); 
      this.name = value; 
      this.RaisePropertyChanged(propertyName); 
     } 
    } 
} 
private String name = null; 
+1

संपादित किया गया यह समाधान केवल स्ट्रिंग के रूप में संपत्ति नाम को सेट करने से अधिक नाजुक है। – Charlie

+0

यह दिलचस्प लग रहा है। दस्तावेज की जांच किए बिना, हालांकि, मैं यह नहीं समझ सकता कि सबस्ट्रिंग के लिए कॉल क्या है। GetMethod()। नाम कुछ अजीब लौटाता है? –

+0

एक संपत्ति दो तरीकों से लागू की जाती है। सार्वजनिक MyType MyProperty {प्राप्त करें; सेट; } को सार्वजनिक शून्य सेट_MyProperty (MyType मान) {} और सार्वजनिक MyType get_MyProperty() के रूप में लागू किया गया है। इसलिए आपको संपत्ति का नाम प्राप्त करने के लिए लौटाए गए विधि नाम से set_ और get_ को हटाना होगा। –

1

सिद्धांत रूप में, आप (4) संपत्ति सेटर के भीतर से MethodBase.GetCurrentMethod()। Name.Substring इस्तेमाल कर सकते हैं। दुर्भाग्यवश, Google खोज से पता चलता है कि it seems to have a significant performance impact।विचार करने के लिए दो और चीजें:

  • जेआईटी इनलाइनिंग अप्रत्याशित तरीकों से इसका असर डाल सकती है। (stackoverflow.com/questions/616779/can-i-check-if-the-c-compiler-inlined-a-method-call)
  • सिद्धांत रूप में, आईएल कॉल को MethodBase.GetCurrentMethod() को छोटा रूप से बदला जा सकता है जेआईटी द्वारा रनटाइम पर एक ldtoken निर्देश के साथ MethodBase.GetMethodFromHandle(), जो बहुत तेज़ होगा। मुझे लगता है कि उपयोगकर्ताओं ने अभी इसकी आवश्यकता व्यक्त नहीं की है। (msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldtoken.aspx)
  • पूरी तरह से मेरी राय यहां है, लेकिन मुझे लगता है कि फ़ील्डफ() और विधि() सी # में ऑपरेटर। मेरा मानना ​​है कि यह उन परियोजनाओं में कोड विश्लेषण/रीफैक्टरिंग टूल्स की विश्वसनीयता में काफी सुधार करेगा जिसके लिए उस क्षमता की आवश्यकता होती है।
0

आपको यह blog post देखना चाहिए। तो आप के लिए काम करना चाहिए

string propertyName = TypeHelper.GetPropertyName<User>(u => u.LastProjectCode); 

PropertyInfo property1 = TypeHelper.GetProperty((SomeClass o) => o.InstanceProperty.Length); 

PropertyInfo property2 = TypeHelper.GetProperty(() => SomeClass.StaticProperty.Length); 

में दृश्य स्टूडियो/Resharper/Refactor प्रो नाम बदलता है: यह आप ऐसा करने की क्षमता देता है।

6

सी # 5 में एक समाधान लगता है। CallerMemberName attribute के साथ जिसका उपयोग पैरामीटर (One example on the net) के साथ किया जा सकता है।

class Employee : INotifyPropertyChanged 
{ 
    private string _Name; 
    public string Name 
    { 
     get { return _Name; } 

     set 
     { 
      _Name = value; 
      RaisePropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void RaisePropertyChanged([CallerMemberName] string caller = "") 
    { 
     var temp = PropertyChanged; 

     if (temp != null) 
     { 
      temp(this, new PropertyChangedEventArgs(caller)); 
     } 
    } 
} 
+0

वाह! आपका सबसे अच्छा लगता है। – VivekDev

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