2011-11-30 8 views
17

मैं एक लैम्ब्डा नौसिखिया हूं, इसलिए यदि मुझे मेरे विवरण में महत्वपूर्ण जानकारी याद आ रही है तो कृपया मुझे बताएं। मैं उदाहरण को यथासंभव सरल रखूंगा।नेट लैम्ब्डा अभिव्यक्ति - यह पैरामीटर कहां से आया?

मैं किसी और के कोड पर जा रहा हूं और उनके पास एक वर्ग से विरासत में एक वर्ग है। इधर, पहले व्युत्पन्न वर्ग है लैम्ब्डा अभिव्यक्ति मुझे समझने में कठिनाई हो रही है के साथ:

class SampleViewModel : ViewModelBase 
{ 
    private ICustomerStorage storage = ModelFactory<ICustomerStorage>.Create(); 

    public ICustomer CurrentCustomer 
    { 
     get { return (ICustomer)GetValue(CurrentCustomerProperty); } 
     set { SetValue(CurrentCustomerProperty, value); } 
    } 

    private int quantitySaved; 
    public int QuantitySaved 
    { 
     get { return quantitySaved; } 
     set 
     { 
      if (quantitySaved != value) 
      { 
       quantitySaved = value; 
       NotifyPropertyChanged(p => QuantitySaved); //where does 'p' come from? 
      } 
     } 
    } 

    public static readonly DependencyProperty CurrentCustomerProperty; 

    static SampleViewModel() 
    { 
     CurrentCustomerProperty = DependencyProperty.Register("CurrentCustomer", typeof(ICustomer), 
      typeof(SampleViewModel), new UIPropertyMetadata(ModelFactory<ICustomer>.Create())); 
    } 
//more method definitions follow.. 

नोट कॉल करने के लिए NotifyPropertyChanged(p => QuantitySaved) सा ऊपर। मुझे समझ में नहीं आता कि "पी" कहां से आ रहा है।

यहाँ आधार वर्ग है:

public abstract class ViewModelBase : DependencyObject, INotifyPropertyChanged, IXtremeMvvmViewModel 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void NotifyPropertyChanged<T>(Expression<Func<ViewModelBase, T>> property) 
     { 
      MvvmHelper.NotifyPropertyChanged(property, PropertyChanged); 
     } 
    } 

वहाँ उस सवाल का मुझे यकीन है कि करने के लिए उचित नहीं है वहाँ में एक बहुत है, लेकिन मैं समग्रता की ओर गलती करना चाहता था।

समस्या यह है कि, मुझे समझ में नहीं आता कि 'पी' पैरामीटर कहां से आ रहा है, और संकलक कैसे जानता है (स्पष्ट रूप से?) पतली हवा से ViewModelBase के प्रकार मान को भरें?

मस्ती के लिए मैं, 'यह' करने के लिए 'पी' से कोड बदल के बाद से SampleViewModel ViewModelBase से विरासत, लेकिन मैं संकलक त्रुटियों की एक श्रृंखला है, जिनमें से पहले एक Invalid expression term '=>' यह कहा गया है का सामना करना पड़ा मुझे के बाद से मैं थोड़ा उलझन में सोचा कि काम करेगा।

क्या कोई यह समझा सकता है कि यहां क्या हो रहा है?

उत्तर

8

लैम्ब्डा p => QuantitySaved टाइप Expression<Func<ViewModelBase, int>> की अभिव्यक्ति है। चूंकि विधि NotifyPropertyChanged<ViewModelBase, T> की अभिव्यक्ति की तलाश में है, यह फिट बैठता है।

तो कंपाइलर अनुमान लगा सकता है कि pViewModelBase है। p कहीं से भी "नहीं आया", इसे मूल रूप से यहां घोषित किया जा रहा है। यह लैम्ब्डा के लिए एक पैरामीटर है। जब कोई आपकी विधि के property पैरामीटर का उपयोग करता है तो यह भरने जा रहा है। उदाहरण के लिए, यदि आप अपना लैम्ब्डा lambda नामक एक अलग चर में डालते हैं, तो आप इसे lambda(this) के साथ कॉल कर सकते हैं और यह QuantitySaved मान वापस कर देगा।

कारण आप लैम्ब्डा में this का उपयोग नहीं कर सकते हैं क्योंकि यह पैरामीटर नाम की उम्मीद कर रहा है, और this मान्य नाम नहीं है। मुद्दा यह है कि आप इसे ViewModelBase के किसी भी उदाहरण पर कॉल कर सकते हैं, न कि केवल लैम्ब्डा बनाया है।

p => QuantitySaved // lambda 
इस के साथ

:

delegate (ViewModelBase p) { return QuantitySaved; } // anonymous delegate 

प्रभावी रूप से एक ही है कौन सा

+0

आह, ठीक है। तो यह एक विधि घोषणा है। मैंने सोचा था कि सवाल में स्निपेट था - उस पल - अधिसूचनाप्रॉपर्टी चंगेड() को पैरामीटर के रूप में 'पी' के साथ कॉल करना। सभी को धन्यवाद, मेरी आंखें थक गई होंगी। – larryq

+0

नहीं, आप 'इस' का उपयोग नहीं कर सकते क्योंकि यह एक आरक्षित कीवर्ड है। यह पैरामीटर नाम के रूप में कभी मान्य नहीं है। – jason

+3

@larryq: यह NotifyProperty को कॉल कर रहा है * अभिव्यक्ति वृक्ष * के साथ बदल दिया गया है जिसमें एक * पैरामीटर * पी कहा जाता है। NotifyPropertyChanged से औपचारिक पैरामीटर 'संपत्ति' की घोषणा को अलग करने से आप लैम्बडा से पी को अलग नहीं कर सकते हैं। –

3

NotifyPropertyChanged हस्ताक्षर से:

void NotifyPropertyChanged<T>(Expression<Func<ViewModelBase, T>> property) 

विधि एक अभिव्यक्ति है कि प्रकार ViewModelBase की एक इनपुट लेता है और प्रकार T का एक उदाहरण देता है उम्मीद है।

पी पैरामीटर ViewModelBase का एक उदाहरण है।

10

p सिर्फ एक डमी नाम है, यह किसी भी विधि में पैरामीटर का नाम है। यदि आप चाहें तो आप इसे x या Fred नाम दे सकते हैं।

याद रखें, लैम्ब्डा अभिव्यक्तियां बहुत ही बहुत ही अज्ञात विधियां हैं।

नियमित तरीकों आप पैरामीटर में, और वे नाम हैं:

public double GetQuantitysaved(ViewModelBase p) { 
    return QuantitySaved; 
} 

गुमनाम तरीकों आप पैरामीटर में, और वे नाम हैं:

delegate(ViewModelBase p) { return QuantitySaved; } 

लैम्ब्डा में भाव आप पैरामीटर है, और उनके नाम हैं:

p => QuantitySaved 

p यहां सा मुझे सभी तीन संस्करणों में भूमिका। आप इसे जो कुछ भी चाहते हैं उसका नाम दे सकते हैं। यह विधि के लिए पैरामीटर का नाम है।

पिछले मामले में, संकलक यह पता लगाने की है कि p प्रकार ViewModelBase की एक पैरामीटर का प्रतिनिधित्व करता है ताकि p => QuantitySaved मस्ती के लिए

Expression<Func<ViewModelBase, T>> property 

की भूमिका निभा सकते हैं मैं कोड बदल बहुत काम करता है p से this, SampleViewModelViewModelBase से विरासत में मिला, लेकिन मुझे कंपाइलर त्रुटियों की एक श्रृंखला से मुलाकात की गई, जिसमें से पहला Invalid expression term '=>' यह मुझे थोड़ा उलझन में लगा क्योंकि मैंने सोचा था कि यह काम करेगा।

अच्छा, this मान्य पैरामीटर नाम नहीं है क्योंकि यह एक आरक्षित कीवर्ड है। यह रूप में

delegate(ViewModelBase p) { return QuantitySaved; } 

p => QuantitySaved के बारे में सोच जब तक आप इस विचार के साथ सहज होने के लिए सबसे अच्छा है। इस मामले में, को p के लिए कभी भी प्रतिस्थापित नहीं किया जा सकता क्योंकि यह मान्य पैरामीटर नाम नहीं है।

4

इस को समझने के लिए आसान तरीका यह बदलने के लिए है। p आपके अज्ञात प्रतिनिधि के पहले पैरामीटर के लिए पैरामीटर नाम है। आप इसे पैरामीटर नामों के लिए उचित नाम दे सकते हैं (this एक कीवर्ड है, आप इसे पैरामीटर नाम के रूप में उपयोग नहीं कर सकते हैं)

इस विशेष उदाहरण में इस p वैरिएबल को अनावश्यक है, आप पैरामीटर रहित प्रतिनिधि का भी उपयोग कर सकते हैं।

+0

इस मामले में, यह वही नहीं है, क्योंकि लैम्ब्डा को एक प्रतिनिधि में परिवर्तित नहीं किया गया है, बल्कि 'अभिव्यक्ति' है। और आप 'प्रतिनिधि' अज्ञात कार्यों के साथ ऐसा नहीं कर सकते हैं। – svick

17

जहां 'पी' NotifyPropertyChanged(p => QuantitySaved);

में लैम्ब्डा एक विधि NotifyPropertyChanged कहा जाता है के लिए पारित किया जा रहा है से आता है। उस विधि का एक अधिभार है। इसमें औपचारिक पैरामीटर प्रकार Expression<Func<ViewModelBase, T>> है। यही है, औपचारिक पैरामीटर एक लैम्ब्डा प्राप्त करने की अपेक्षा करता है जो व्यूमोडेलबेस लेता है और कुछ टी के लिए टी देता है।

p लैम्ब्डा लेता है पैरामीटर है।

संकलक यह अनुमान लगाने में सक्षम है कि कोड के लेखक ने स्पष्ट रूप से लैम्ब्डा पैरामीटर के प्रकार को वर्तनी करने के लिए उपेक्षित किया है। लेखक भी लिख सकता:

NotifyPropertyChanged((ViewModelBase p) => QuantitySaved);

था वे इसके बारे में स्पष्ट होना चाहता था।

संकलक पतली हवा से ViewModelBase के प्रकार मान को भरने के बारे में कैसे जानता है?

संकलक NotifyPropertyChanged के सभी संभव भार के कि संभवतः उस कथन की स्थिति में एक लैम्ब्डा ले सकता है जांच करता है। विधियों के औपचारिक पैरामीटर प्रकारों में प्रतिनिधि से लैम्ब्डा के औपचारिक पैरामीटर प्रकार का अनुमान लगाता है। एक उदाहरण मदद कर सकता है। मान लीजिए हमने:

void M(Func<int, double> f) {} 
void M(Func<string, int> f) {} 

और एक कॉल

M(x=>x.Length); 

संकलक की लैम्ब्डा पैरामीटर एक्स प्रकार का अनुमान लगा होना चाहिए। संभावनाएं क्या हैं? एम के दो अधिभार हैं। दोनों कॉल में पारित पहले तर्क के अनुरूप एम के औपचारिक पैरामीटर में एक प्रतिनिधि लेते हैं। पहले में, फ़ंक्शन int से डबल तक होता है, इसलिए x टाइप int का हो सकता है। दूसरे में, एम का औपचारिक पैरामीटर स्ट्रिंग से int तक एक फ़ंक्शन है, इसलिए एक्स स्ट्रिंग हो सकता है।

कंपाइलर को अब यह निर्धारित करना होगा कि कौन सा सही है। पहले व्यक्ति को सही होने के लिए, लैम्ब्डा का शरीर एक डबल वापस करना होगा। लेकिन यदि एक्स int है, तो x पर कोई प्रॉपर्टी लम्बाई नहीं है जो एक डबल देता है। तो एक्स int नहीं हो सकता है। क्या एक्स स्ट्रिंग हो सकता है? हाँ। X पर एक प्रॉपर्टी लम्बाई है जो x int स्ट्रिंग होने पर int को लौटाती है।

इसलिए संकलक कटौती करता है कि एक्स स्ट्रिंग है।

ये कटौती असाधारण रूप से जटिल हो सकती है। एक थोड़ा और अधिक जटिल उदाहरण:

void M<A, B, C>(A a1, Func<List<A>, B> a2, Func<B, C> a3) {} 
... 
M(123, x=>x.Count.ToString(), y=>y.Length); 

प्रकार अनुमान टाइप ए, बी, सी और इसलिए x और y के प्रकार का अनुमान लगा होना चाहिए। संकलक पहले अनुमान लगाता है कि ए 1 होना चाहिए क्योंकि ए 1 123 है। फिर यह अनुमान लगाता है कि एक्स उस तथ्य से List<int> होना चाहिए। इसके बाद यह अनुमान लगाता है कि बी स्ट्रिंग होना चाहिए, और इसलिए y स्ट्रिंग है, और इसलिए सी y.Length का प्रकार है, जो int है।

यह वहां से बहुत अधिक जटिल हो जाता है, मेरा विश्वास करो।

यदि यह विषय आपको रूचि देता है, तो मैंने कई लेख लिखे हैं और संकलक द्वारा किए गए विभिन्न प्रकार के प्रकार के अनुमान के विषय पर कुछ वीडियो फिल्माए हैं। सभी विवरण के लिए

http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/

देखें।

मस्ती के लिए मैं, 'यह' करने के लिए 'पी' से कोड बदल के बाद से SampleViewModel ViewModelBase से विरासत, लेकिन मैं संकलक त्रुटियों की एक श्रृंखला है, जिनमें से पहले एक statedInvalid अभिव्यक्ति शब्द '=>' का सामना करना पड़ा इससे मुझे थोड़ा उलझन में आया क्योंकि मैंने सोचा था कि काम करेगा।

लैम्ब्डा ऑपरेटर का एकमात्र स्वीकार्य बाएं हाथ की तरफ एक लैम्ब्डा पैरामीटर सूची है; "यह" कभी कानूनी लैम्ब्डा पैरामीटर सूची नहीं है। संकलक "इस" का पालन करने की उम्मीद कर रहा है ".SomeMethod()" या ऐसी कुछ चीज; संकलक मानता है कि "यह" कभी भी "=>" का पालन नहीं करेगा। जब आप उस धारणा का उल्लंघन करते हैं, तो बुरी चीजें होती हैं।

+0

स्पष्टीकरण एरिक के लिए बहुत धन्यवाद। बहुत सराहना की। – larryq

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