2010-12-03 10 views
5

डेटा फ़ाइल: (data.txt) लाइनों का प्रतिनिधित्व width heightसी # 4.0 उलझाव से टाइप गतिशील ऑब्जेक्ट्स

5 
6 9 
7 2 
4 4 

सी # कोड:

var list = new List<dynamic>(); 
using (var sr = new StreamReader("Data.txt", Encoding.UTF8)) 
{ 
    list = sr.ReadToEnd().Split('\n').Select(r => 
    { 
     var split = r.Split(' '); 
     var len = split.Length; 
     return new { 
      w = len > 0 ? int.Parse(split[0].Trim()) : 0, 
      h = len > 1 ? int.Parse(split[1].Trim()) : 0 
     } as dynamic; 
    }).ToList(); 
} 
int Area = list.Sum(r => r.h * r.w); 

उदाहरण काम करता है के रूप में। मुझे इसे काम करने के लिए कुछ अवांछित चीजें करना पड़ा।

सबसे पहले मुझे उपयोग के दायरे से बचने के लिए सूची घोषित करना पड़ा - क्योंकि मेरे पास टाइपेड आयाम ऑब्जेक्ट नहीं है, मैंने टाइप गतिशील (var list = new List<dynamic>()) बनाया है।

अवांछनीय हिस्सा अज्ञात ऑब्जेक्ट को गतिशील (as dynamic) पर कास्टिंग कर रहा है। अन्यथा मैं

परोक्ष प्रकार कनवर्ट नहीं कर सकता System.Collections.Generic.List<AnonymousType#1> System.Collections.Generic.List<dynamic>

को क्यों मैं इस त्रुटि मिलती है मिल सकता है? मुझे पता है कि एक गतिशील गुमनाम प्रकार पकड़ सकता है, तो क्या यह ToList() एक्सटेंशन और गतिशीलता के साथ एक समस्या है?

मुझे क्षेत्र की गणना करने वाली अंतिम पंक्ति में, उपयोग कथन के बाहर अज्ञात सूची आइटम तक पहुंचने में सक्षम होना चाहिए।


समाधान: मैं DTB के जवाब के साथ चला गया। यह सभी एक साथ उपयोग कथन और गतिशीलता के उपयोग से परहेज किया। निवेश के लिए आप सभी को धन्यवाद!

var list = 
    (from line in File.ReadLines("Data.txt") 
    let parts = line.Split(' ') 
    let width = int.Parse(parts[0]) 
    let height = parts.Length > 1 ? int.Parse(parts[1]) : 0 
    select new { width, height }).ToList(); 
+0

तुम क्यों इस तरह गतिशील उपयोग कर रहे हैं? – ChaosPandion

+7

गतिशील का अनुचित उपयोग। आप * प्रकार * जानते हैं, इसे गतिशील बनाने के लिए कोई लाभ नहीं है। एक संरचना या टुपल <> का प्रयोग करें। –

+0

तो क्या आप कह रहे हैं कि अनाम प्रकार के साथ ऐसा करने का कोई तरीका नहीं है? –

उत्तर

6

आप StreamReader से बचने के लिए File.ReadLines का उपयोग कर सकते हैं।

IEnumerable<dynamic> query = 
    from line in File.ReadLines("Data.txt") 
    let parts = line.Split(' ') 
    let width = int.Parse(parts[0]) 
    let height = parts.Length > 1 ? int.Parse(parts[1]) : 0 
    select new { width, height } as dynamic; 

List<dynamic> list = query.ToList(); 

int area = list.Sum(t => t.width * t.height); 

हालांकि, जैसा कि अन्य ने इंगित किया है, गतिशीलता का उपयोग करना वास्तव में यहां उचित नहीं है। यदि आप केवल एक विधि के भीतर क्वेरी का उपयोग कर रहे हैं, तो एक अनाम उदाहरण पर्याप्त है। यदि आप विधि के बाहर क्वेरी के परिणाम का उपयोग करना चाहते हैं, तो एक छोटी संरचना या कक्षा बनाएं या टुपल < टी 1, टी 2 > का उपयोग करें।

+0

बहुत अच्छा लेकिन वे अभी भी गतिशील का उपयोग नहीं करना चाहिए। – ChaosPandion

+0

मुझे यह जवाब पसंद है क्योंकि यह उपयोग ब्लॉक से बचाता है - पूरे कारण से मैंने गतिशील को पहली जगह पेश की। –

1

इसे सह/contravariance के साथ करना है।

आप List<T1> से List<T2> पर नहीं डाल सकते हैं।

List<object> objectList = new List<string>{"hello"}; 

साथ की कोशिश करो और आप संकलन त्रुटि

यह त्रुटि

List<string> stringList = new List<string>{"hello"}; 
List<object> objectList = stringList; // compile error 
objectList.Add(new Car()); // this would add a Car object to the stringList if the above line was allowed 
2

को रोकने के लिए मैं छुटकारा पाने चाहते हैं कि "परोक्ष 'System.Collections.Generic.List<object>' के लिए प्रकार 'System.Collections.Generic.List<string>' कनवर्ट नहीं कर सकता" मिल पहली पंक्ति के बाद, जहां सूची सौंपा गया है, इसे var के साथ घोषित करें और अंतिम पंक्ति को उपयोग कथन के अंदर ले जाएं:

int Area; 
using (var sr = new StreamReader("Data.txt", Encoding.UTF8)) 
{ 
    var list = sr.ReadToEnd().Split('\n').Select(r => 
    { 
     var split = r.Split(' '); 
     var len = split.Length; 
     return new { 
      w = len > 0 ? int.Parse(split[0].Trim()) : 0, 
      h = len > 1 ? int.Parse(split[1].Trim()) : 0 
     }; 
    }).ToList(); 
    Area = list.Sum(r => r.h * r.w); 
} 
+0

मुझे लगता है कि यह सबसे अच्छा विकल्प है। यह 'गतिशील' के अवांछित उपयोग को समाप्त करता है, 'टुपल <>' के उपयोग से बचाता है, और कार्यात्मक रूप से समतुल्य है। – LBushkin

+0

@LBushkin: धन्यवाद :) –

+0

@LBushkin - मुझे बस क्षेत्र की गणना करने के अलावा बहुत कुछ करना है। मुझे नहीं लगता कि जवाब पूरे कार्यक्रम को उपयोग में लिखना है। –

1

कारण आप केवल असाइन नहीं कर सकते हैं:

पहले मामले में, आपको List<SomeAnonymousType> मिल रहा है। यह प्रकार List<dynamic> से पूरी तरह से असंबंधित है, भले ही अनाम प्रकार से dynamic पर एक अंतर्निहित रूपांतरण मौजूद है। यह थोड़ा सा List<int> को List<float> में रूपांतरित करने जैसा है।

0

गतिशील आपका समाधान यहां नहीं है। आपको बस उपयोग कथन के अंदर क्षेत्र की गणना करना है।

का उपयोग कर विवरण के बाहर यह एक बुरा विचार है यदि आप यहां स्थगित निष्पादन को पेश करने का प्रयास कर रहे हैं; आप कॉल को कॉल करने से पहले स्ट्रीमरडर की डिप्लोज़िंग समाप्त कर देंगे।

अंत में, अपने कोड इस तरह दिखना चाहिए:

int Area = 0; 

using (var sr = new StreamReader("Data.txt", Encoding.UTF8)) 
{ 
    Area = sr.ReadToEnd().Split('\n').Select(r => 
    { 
     var split = r.Split(' '); 
     var len = split.Length; 
     return new { 
      w = len > 0 ? int.Parse(split[0].Trim()) : 0, 
      h = len > 1 ? int.Parse(split[1].Trim()) : 0 
     } as dynamic; 
    }).Sum(r => r.h * r.w); 
} 

यह इस तरह से बेहतर है कर रहा है, तो आप सूची materializing नहीं कर रहे हैं और उसके बाद फिर इसके माध्यम से पाशन, आप डेटा खींच रहे हैं और यह संक्षेप जैसी जरूरत थी।

+0

के अंदर नए आयाम लौटाएं, मुझे बस क्षेत्र की गणना करने के अलावा बहुत कुछ करना है। मैं अन्य गणनाओं के लिए सूची आयामों का उपयोग करने के लिए आगे बढ़ जाऊंगा। क्षेत्र सिर्फ एक उदाहरण था। मुझे नहीं लगता कि जवाब पूरे कार्यक्रम को उपयोग में लिखना है। –

+1

@ जोशियाह रुडेल: नहीं, ऐसा नहीं है, इस मामले में आपको दृढ़ता से उस संरचना को टाइप करना चाहिए जिसे आप फ़ाइल से क्रमबद्ध कर रहे हैं, और उसके बाद आइटम को पाठक से पढ़ते समय उपज दें। उपज का उपयोग करके, स्ट्रीमराइडर तब तक खोला नहीं जाएगा जब तक गणना गणना नहीं हो जाती है और जब तक गणना का निपटारा नहीं किया जाता है तब तक बंद नहीं किया जाता है (जो आपके लिए foreach करता है)। – casperOne

3

आप वास्तव में कुछ इस तरह करना चाहिए:

private IEnumerable<Tuple<int, int>> ReadFile(string filePath, 
    Encoding encoding) 
{ 
    using (var sr = new StreamReader(filePath, encoding)) 
    { 
     string line; 
     while ((line = sr.ReadLine()) != null) 
     { 
      var split = line.Split(' '); 
      var w = split.Length > 0 ? int.Parse(split[0]) : 0; 
      var h = split.Length > 1 ? int.Parse(split[1]) : 0; 
      yield return Tuple.Create(h, w); 
     } 
    } 
} 

अब तुम मूल्यों की एक आलसी और दृढ़ता से टाइप किया अनुक्रम है।

+0

मुझे यह जवाब भी पसंद है +1 –

0

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

आप .ToList को कॉल करने से पहले .Cast() जोड़कर अपने कोड काम कर सकते हैं()

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