2017-08-30 69 views
7

को देखते हुए निम्नलिखित इंटरफेस और दो वर्गों (प्रत्येक चरण में दो वस्तुओं का चयन):LINQ के साथ एक foreach पाश को सरल बनाना

public interface IMyObj 
{ 
    int Id { get; set; } 
} 

public class MyObj1 : IMyObj 
{ 
    public MyObj1(int id) { Id = id; } 
    public int Id { get; set; } 
    public override string ToString() => $"{GetType().Name} : {Id}"; 
} 

public class MyObj2 : IMyObj 
{ 
    public MyObj2(int id) { Id = id; } 
    public int Id { get; set; } 
    public override string ToString() => $"{GetType().Name} : {Id}"; 
} 

और तर्क उन्हें का उपयोग करता है निम्नलिखित दिया:

var numbers = new[] { 1, 5, 11, 17 }; 

var list = new List<IMyObj>(); 

foreach (var n in numbers) 
{ 
    // I'd like to simplify this part with LINQ... 
    list.Add(new MyObj1(n)); 
    list.Add(new MyObj2(n)); 
} 

Assert.AreEqual(8, list.Count); 

परीक्षण में सफ़ल , और मैं list के अंदर देखता हूं जो वास्तव में चाहता है - दो ऑब्जेक्ट उदाहरण प्रति संख्या:

Count = 8 
    [0]: {MyObj1 : 1} 
    [1]: {MyObj2 : 1} 
    [2]: {MyObj1 : 5} 
    [3]: {MyObj2 : 5} 
    [4]: {MyObj1 : 11} 
    [5]: {MyObj2 : 11} 
    [6]: {MyObj1 : 17} 
    [7]: {MyObj2 : 17} 

मेरा सवाल है, मैं LINQ के साथ foreach लूप तर्क को सरल कैसे बना सकता हूं? मैं सोच रहा हूं कि SelectMany ऑपरेटर के साथ ऐसा करने में एक शानदार तरीका हो सकता है, लेकिन मैं एक ही आउटपुट का उत्पादन करने में सक्षम नहीं हूं।

var list = numbers.SelectMany(n => new IMyObj[] { new MyObj1(n), new MyObj2(n) }) 
        .ToList(); 

दूसरे शब्दों में, प्रत्येक संख्या के लिए, एक दो तत्व सरणी है, जो तब SelectMany के लिए प्रयोग कर चपटा है बनाने के लिए:

उत्तर

15

SelectMany आप क्या चाहते हैं वास्तव में है।

new IMyObj[] भाग new[] के बजाय भाग की आवश्यकता है क्योंकि टाइप अनुमान यह नहीं बता सकता कि आप किस सरणी प्रकार को चाहते हैं। यदि प्रकार एक ही थे, तो आप की तरह कुछ कर सकता है:

var list = numbers.SelectMany(n => new[] { new MyObj(n), new MyObj(n) }) 
        .ToList(); 
0

आप [Union][1] का उपयोग कर दो सूचियों को श्रेणीबद्ध कर सकते हैं:

var result = numbers.Select(x => (IMyObj) new MyObj1(x)) 
    .Union(numbers.Select(x => x => new MyObj2(x))); 

Alternativly एक एक करके:

var l1 = numbers.Select(x => new MyObj1(x)).Cast<IMyObject>().ToList(); 
var l2 = numbers.Select(x => new MyObj(x)); 

var result = l1.Concat(l2); 

या l1.AddRange(l2)

बेशक उन सभी दृष्टिकोणों के पास आपके ऑर्डर के समान ही नहीं था जैसा कि MyObj1 से पहले सभी उदाहरण संग्रहीत किए जाते हैं और फिर MyOb2 के सभी उदाहरण संग्रहीत किए जाते हैं।

+4

ध्यान दें कि यह ओपी के मूल कोड के समान आदेश नहीं देता है, 'SelectMany' के विपरीत। मैं 'यूनियन' के बजाय 'कंसट' का उपयोग करने का भी सुझाव दूंगा क्योंकि सेट-वार व्यवहार निर्दिष्ट नहीं किया गया है ... और आखिरकार, आपको इंटरफ़ेस का उपयोग करके प्रकार तर्कों को निर्दिष्ट करने की आवश्यकता है अन्यथा जो संकलित नहीं होंगे। –

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