IEnumerable <T> के रूप में किसी एक आइटम को पास करना


377

क्या किसी प्रकार की एकल वस्तु Tको एक विधि से पारित करने का एक सामान्य तरीका है जो एक IEnumerable<T>पैरामीटर की अपेक्षा करता है? भाषा C #, फ्रेमवर्क संस्करण 2.0 है।

वर्तमान में मैं एक सहायक विधि का उपयोग कर रहा हूँ (यह .Net 2.0 है, इसलिए मेरे पास LINQ के समान सहायक विधियों की कास्टिंग / प्रोजेक्ट करने का एक पूरा गुच्छा है), लेकिन यह सिर्फ मूर्खतापूर्ण लगता है:

public static class IEnumerableExt
{
    // usage: IEnumerableExt.FromSingleItem(someObject);
    public static IEnumerable<T> FromSingleItem<T>(T item)
    {
        yield return item; 
    }
}

अन्य तरीका निश्चित रूप से एक List<T>या एक को बनाना और पॉप्युलेट Arrayकरना होगा और इसके बजाय इसे पास करना होगा IEnumerable<T>

[संपादित करें] एक विस्तार विधि के रूप में इसका नाम हो सकता है:

public static class IEnumerableExt
{
    // usage: someObject.SingleItemAsEnumerable();
    public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
    {
        yield return item; 
    }
}

क्या मुझसे कोई चूक हो रही है?

[Edit2] हमने पाया someObject.Yield()(जैसा कि @Peter ने नीचे टिप्पणी में सुझाया है) इस विस्तार पद्धति का सबसे अच्छा नाम होना, मुख्य रूप से संक्षिप्तता के लिए, इसलिए यहाँ XML टिप्पणी के साथ है अगर कोई इसे हथियाना चाहता है:

public static class IEnumerableExt
{
    /// <summary>
    /// Wraps this object instance into an IEnumerable&lt;T&gt;
    /// consisting of a single item.
    /// </summary>
    /// <typeparam name="T"> Type of the object. </typeparam>
    /// <param name="item"> The instance that will be wrapped. </param>
    /// <returns> An IEnumerable&lt;T&gt; consisting of a single item. </returns>
    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }
}

6
मैं विस्तार विधि के शरीर में एक मामूली संशोधन करूँगा: if (item == null) yield break; अब आपको अशक्त होने से रोकने के साथ-साथ (तुच्छ) अशक्त वस्तु पैटर्न का लाभ लेना बंद कर दिया जाएगा IEnumerable। ( foreach (var x in xs)एक खाली xsठीक संभालती है)। संयोग से, यह फ़ंक्शन उस सूची के लिए monadic इकाई है जो कि monad है IEnumerable<T>, और Microsoft में monad love-उत्सव को देखते हुए मुझे आश्चर्य है कि यह कुछ इस तरह से पहली जगह में नहीं है।
मैट एनराइट

2
एक्सटेंशन विधि के लिए, आपको इसका नाम नहीं देना चाहिए AsEnumerableक्योंकि उस नाम के साथ एक अंतर्निहित एक्सटेंशन पहले से मौजूद है । (जब Tलागू होता है IEnumerable, उदा string।)
जॉन-एरिक

22
कैसे नामकरण विधि के बारे में Yield? कुछ भी नहीं संक्षिप्तता धड़कता है।
फिलिप गिनी

4
यहां नामकरण के सुझाव। "एकलइमेसएनिएमरेबल" थोड़ा वर्बोज़। "यील्ड" इंटरफ़ेस के बजाय कार्यान्वयन का वर्णन करता है - जो अच्छा नहीं है। बेहतर नाम के लिए, मैं "असिंगटन" का सुझाव देता हूं, जो व्यवहार के सटीक अर्थ के अनुरूप है।
पृथ्वी इंजन

4
मुझे left==nullयहां चैक से नफरत है। यह कोड की सुंदरियों को तोड़ता है और कोड को अधिक लचीले होने से रोकता है - क्या होगा अगर किसी दिन आप किसी एकल के साथ एक सिंगलटन उत्पन्न करने की आवश्यकता है जो अशक्त हो सकता है? मेरा मतलब है, new T[] { null }जैसा है वैसा नहीं है new T[] {}, और किसी दिन आपको उन्हें अलग करने की आवश्यकता हो सकती है।
पृथ्वी इंजन

जवाबों:


100

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


यदि सूची / सरणी को तदर्थ बनाया गया है, तो इसका दायरा विधि कॉल के बाद समाप्त हो जाता है, इसलिए इससे समस्याएँ नहीं होनी चाहिए
मारियो एफ

यदि एक सरणी के रूप में भेजा जाता है, तो इसे कैसे बदला जा सकता है? मुझे लगता है कि यह एक सरणी में डाली जा सकती है, और फिर संदर्भ को किसी और चीज़ में बदल सकती है, लेकिन इससे अच्छा क्या होगा? (मैं शायद कुछ याद कर रहा हूँ ...)
Svish

2
मान लीजिए आपने दो अलग-अलग तरीकों से पारित होने के लिए एक गणना करने योग्य बनाने का फैसला किया ... तो पहले वाले ने इसे एक सरणी में डाला और सामग्री को बदल दिया। फिर आप इसे परिवर्तन से अनजान एक अन्य विधि के तर्क के रूप में पास करते हैं। मैं यह नहीं कह रहा हूँ कि यह संभव है, बस कुछ ऐसा होने योग्य है जब इसे होने की आवश्यकता नटला अपरिवर्तनीयता से कम साफ न हो।
जॉन स्कीट

3
यह एक स्वीकृत उत्तर है, और सबसे अधिक पढ़ने की संभावना है, इसलिए मैं अपनी चिंता यहां जोड़ूंगा। मैंने इस तरीके को आजमाया, लेकिन इसने मेरे पहले के संकलन को तोड़ दिया myDict.Keys.AsEnumerable()जहां myDictटाइप का था Dictionary<CheckBox, Tuple<int, int>>। मैंने एक्सटेंशन विधि का नाम बदलने के बाद SingleItemAsEnumerable, सब कुछ काम करना शुरू कर दिया। IEnumerable <Dictionary <CheckBox, System.Tuple <int, int >>। KeyCollection> 'को' IEnumerable <CheckBox> 'में नहीं बदल सकते। एक स्पष्ट रूपांतरण मौजूद है (क्या आप किसी कलाकार को याद कर रहे हैं?) मैं थोड़ी देर के लिए हैक के साथ रह सकता हूं, लेकिन क्या अन्य पावर हैकर्स बेहतर तरीके से खोज सकते हैं?
हमीश ग्रुबीजन

3
@ HamishGrubijan: ऐसा लगता है कि आप अभी dictionary.Valuesशुरुआत करना चाहते थे । मूल रूप से यह स्पष्ट नहीं है कि क्या चल रहा है, लेकिन मेरा सुझाव है कि आप इसके बारे में एक नया प्रश्न शुरू करें।
जॉन स्कीट

133

ठीक है, अगर विधि को उम्मीद है कि IEnumerableआपको कुछ ऐसा पास करना होगा जो एक सूची है, भले ही इसमें केवल एक तत्व शामिल हो।

मृत्यु

new[] { item }

जैसा कि तर्क पर्याप्त होना चाहिए मुझे लगता है


32
मुझे लगता है कि आप भी टी छोड़ सकते हैं, क्योंकि यह अनुमान लगाया जाएगा (जब तक मैं यहां बहुत गलत नहीं हूं: पी)
Svish

2
मुझे लगता है कि यह सी # 2.0 में नहीं है।
ग्रू

4
"भाषा C # है, फ्रेमवर्क संस्करण 2" C # 3 संकलक T को अनुमान लगा सकता है, और कोड .NET के साथ पूरी तरह से संगत होगा।
sisve

सबसे अच्छा जवाब तल पर है ?!
फाल्को अलेक्जेंडर

2
@Svish मैंने सुझाव दिया और उत्तर देने के लिए संपादित करें कि - हम अभी 2020 में हैं, इसलिए यह "मानक" imho होना चाहिए
OschtärEi

120

C # 3.0 में आप System.Linq.Enumerable वर्ग का उपयोग कर सकते हैं:

// using System.Linq

Enumerable.Repeat(item, 1);

यह एक नया IEnumerable बनाएगा जिसमें केवल आपका आइटम होता है।


26
मुझे लगता है कि यह समाधान कोड को पढ़ने के लिए कठिन बना देगा। :( एक ही तत्व पर दोहराना काफी प्रति-सहज ज्ञान युक्त है जो आपको नहीं लगता?
द्राकर

6
एक बार दोहराने पर मुझे ठीक लगता है। अभी तक एक और विस्तार विधि जोड़ने के बारे में चिंता किए बिना सुगम समाधान, और जहाँ भी आप इसका उपयोग करना चाहते हैं, नाम स्थान सुनिश्चित करना शामिल है।
si618

13
हाँ, मैं वास्तव में सिर्फ new[]{ item }खुद का उपयोग करता हूं, मैंने सिर्फ सोचा था कि एक दिलचस्प समाधान था।
लुकासन

7
यह समाधान पैसा है।
प्रोवेगा

IMHO यह स्वीकृत उत्तर होना चाहिए। कस्टम एक्सटेंशन विधि के बिना, BCL पर एक पंक्ति में पढ़ना, संक्षिप्त करना और इसे लागू करना आसान है।
रयान

35

C # 3 में (मुझे पता है कि आपने 2 कहा था), आप एक जेनेरिक एक्सटेंशन विधि लिख सकते हैं जो वाक्यविन्यास को थोड़ा अधिक स्वीकार्य बना सकती है:

static class IEnumerableExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T item)
    {
        yield return item;
    }
}

ग्राहक कोड तो है item.ToEnumerable()


धन्यवाद, मुझे इस बात की जानकारी है कि (.net 2.0 में काम करता है अगर मैं C # 3.0 का उपयोग करता हूं), मैं बस सोच रहा था कि क्या इसके लिए कोई तंत्र बनाया गया था।
ग्रू ऑक्ट

12
यह वास्तव में अच्छा विकल्प है। मैं केवल करने के लिए नाम बदलने का सुझाव देना चाहते ToEnumerableके साथ खिलवाड़ से बचने के लिएSystem.Linq.Enumerable.AsEnumerable
Fede

3
एक साइड नोट के रूप में, पहले से ही एक ToEnumerableविस्तार विधि मौजूद है IObservable<T>, इसलिए यह विधि नाम मौजूदा सम्मेलनों में भी हस्तक्षेप करता है। ईमानदारी से, मैं सुझाव दूंगा कि विस्तार विधि का उपयोग नहीं किया जाए, क्योंकि यह बहुत सामान्य है।
cwharris

14

यह सहायक विधि आइटम या कई के लिए काम करती है।

public static IEnumerable<T> ToEnumerable<T>(params T[] items)
{
    return items;
}    

1
उपयोगी भिन्नता, क्योंकि यह एक से अधिक वस्तुओं का समर्थन करती है। मुझे यह पसंद है कि यह paramsऐरे के निर्माण पर निर्भर करता है , इसलिए परिणामी कोड क्लीन-लुकिंग है। यह तय नहीं किया गया है कि मुझे यह पसंद है या new T[]{ item1, item2, item3 };कई मदों की तुलना में कम ।
टूलमेकरसैट

होशियार ! इसे प्यार करें
मित्सु फ़रुता

10

मुझे आश्चर्य है कि क्लाइंट एपीआई को सरल बनाने के लिए टाइप टी के एक तर्क के साथ किसी ने विधि के नए अधिभार का सुझाव नहीं दिया।

public void DoSomething<T>(IEnumerable<T> list)
{
    // Do Something
}

public void DoSomething<T>(T item)
{
    DoSomething(new T[] { item });
}

अब आपका क्लाइंट कोड बस यही कर सकता है:

MyItem item = new MyItem();
Obj.DoSomething(item);

या एक सूची के साथ:

List<MyItem> itemList = new List<MyItem>();
Obj.DoSomething(itemList);

19
इससे भी बेहतर, आपके पास हो सकता है DoSomething<T>(params T[] items)जिसका अर्थ है कि संकलक एकल आइटम से सरणी में रूपांतरण को संभाल लेगा। (यह आपको कई अलग-अलग मदों में पारित करने की अनुमति देगा और, फिर से, कंपाइलर उन्हें आपके लिए एक सरणी में परिवर्तित करने का काम करेगा।)
ल्यूक

7

या तो (जैसा कि पहले कहा जा चुका है)

MyMethodThatExpectsAnIEnumerable(new[] { myObject });

या

MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(myObject, 1));

साइड नोट के रूप में, अंतिम संस्करण भी अच्छा हो सकता है यदि आप किसी अनाम वस्तु की खाली सूची चाहते हैं, जैसे

var x = MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(new { a = 0, b = "x" }, 0));

धन्यवाद, हालांकि Enumerable.Repeat .Net 3.5 में नया है। यह ऊपर सहायक विधि के समान व्यवहार करने लगता है।
ग्रू

7

जैसा कि मैंने अभी पाया है, और देखा है कि उपयोगकर्ता ल्यूक ने भी सुझाव दिया है, ऐसा करने का एक अच्छा सरल तरीका इस प्रकार है:

public static void PerformAction(params YourType[] items)
{
    // Forward call to IEnumerable overload
    PerformAction(items.AsEnumerable());
}

public static void PerformAction(IEnumerable<YourType> items)
{
    foreach (YourType item in items)
    {
        // Do stuff
    }
}

यह पैटर्न आपको कई प्रकार से एक ही कार्यक्षमता को कॉल करने की अनुमति देगा: एक एकल आइटम; कई आइटम (अल्पविराम से अलग); एक सरणी; एक सूचि; एक गणना, आदि

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

अद्यतन: AsEnumerable फ़ंक्शन बहुत कुशल दिखता है! ( संदर्भ )


वास्तव में, आपको इसकी आवश्यकता नहीं है .AsEnumerable()। सरणी YourType[]पहले से ही लागू है IEnumerable<YourType>। लेकिन मेरा सवाल उस मामले का जिक्र था जब केवल दूसरी विधि (आपके उदाहरण में) उपलब्ध है, और आप .NET 2.0 का उपयोग कर रहे हैं, और आप एक आइटम पास करना चाहते हैं।
ग्रू नो

2
हाँ, यह करता है, लेकिन आप पाएंगे कि आपको एक स्टैक अतिप्रवाह मिल सकता है ;-)
टीपिकिमोन

और वास्तव में आपके असली सवाल का जवाब देना (ऐसा नहीं जिसे मैं वास्तव में खुद के लिए जवाब देने के लिए देख रहा था!), हाँ, आपको बहुत पसंद है इसे मारियो के जवाब के अनुसार एक सरणी में बदलना होगा
टीपिकिमोन

2
कैसे एक IEnumerable<T> MakeEnumerable<T>(params T[] items) {return items;}विधि को परिभाषित करने के बारे में ? एक तो IEnumerable<T>असतत वस्तुओं के किसी भी संख्या के लिए उम्मीद है कि किसी भी चीज के साथ, का उपयोग कर सकता है । एक आइटम को वापस करने के लिए विशेष वर्ग को परिभाषित करने के लिए कोड अनिवार्य रूप से कुशल होना चाहिए।
सुपरकाट

6

यद्यपि यह एक विधि के लिए ओवरकिल है, मेरा मानना ​​है कि कुछ लोग इंटरएक्टिव एक्सटेंशन को उपयोगी पा सकते हैं।

Microsoft से इंटरएक्टिव एक्सटेंशन (Ix) में निम्न विधि शामिल है।

public static IEnumerable<TResult> Return<TResult>(TResult value)
{
    yield return value;
}

जिसका उपयोग इस तरह किया जा सकता है:

var result = EnumerableEx.Return(0);

Ix मूल Linq एक्सटेंशन विधियों में नहीं मिली नई कार्यक्षमता जोड़ता है, और प्रतिक्रियाशील एक्सटेंशन (Rx) बनाने का एक सीधा परिणाम है।

सोचो, Linq Extension Methods+ Ix= Rxके लिए IEnumerable

आप कोडप्लेक्स पर आरएक्स और आईएक्स दोनों पा सकते हैं ।


5

यह इस C # कंपाइलर ऑप्टिमाइज़ेशन के कारण , और अन्य मामलों में समान प्रदर्शन के कारण उपयोग किए जाने पर 30% तेज़ yieldया अधिक है ।Enumerable.Repeatforeach

public struct SingleSequence<T> : IEnumerable<T> {
    public struct SingleEnumerator : IEnumerator<T> {
        private readonly SingleSequence<T> _parent;
        private bool _couldMove;
        public SingleEnumerator(ref SingleSequence<T> parent) {
            _parent = parent;
            _couldMove = true;
        }
        public T Current => _parent._value;
        object IEnumerator.Current => Current;
        public void Dispose() { }

        public bool MoveNext() {
            if (!_couldMove) return false;
            _couldMove = false;
            return true;
        }
        public void Reset() {
            _couldMove = true;
        }
    }
    private readonly T _value;
    public SingleSequence(T value) {
        _value = value;
    }
    public IEnumerator<T> GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return new SingleEnumerator(ref this);
    }
}

इस परीक्षा में:

    // Fastest among seqs, but still 30x times slower than direct sum
    // 49 mops vs 37 mops for yield, or c.30% faster
    [Test]
    public void SingleSequenceStructForEach() {
        var sw = new Stopwatch();
        sw.Start();
        long sum = 0;
        for (var i = 0; i < 100000000; i++) {
            foreach (var single in new SingleSequence<int>(i)) {
                sum += single;
            }
        }
        sw.Stop();
        Console.WriteLine($"Elapsed {sw.ElapsedMilliseconds}");
        Console.WriteLine($"Mops {100000.0 / sw.ElapsedMilliseconds * 1.0}");
    }

धन्यवाद, तंग छोरों में जीसी बोझ को कम करने के लिए इस मामले के लिए एक संरचना बनाने के लिए समझ में आता है।
ग्रू

1
वापस आने पर प्रगणक और गणनीय दोनों ही बॉक्सिंग करने जा रहे हैं ....
स्टीफन आकर्षित

2
स्टॉपवॉच का उपयोग कर तुलना न करें। Benchmark.NET github.com/dotnet/BenchmarkDotNet
NN_

1
बस इसे मापा जाता है और new [] { i }विकल्प आपके विकल्प के बारे में 3.2 गुना तेजी से होता है। इसके अलावा आपका विकल्प लगभग 1.2 गुना अधिक तेजी से विस्तार के साथ है yield return
लोरंड

आप किसी अन्य C # कंपाइलर ऑप्टिमाइज़ेशन का उपयोग करके इसे गति दे सकते हैं: एक विधि जोड़ें जो SingleEnumerator GetEnumerator()आपकी संरचना को लौटाए। C # कंपाइलर इस विधि का उपयोग करेगा (यह इसे टाइपिंग के माध्यम से देखता है) इंटरफ़ेस वाले के बजाय और इस प्रकार बॉक्सिंग से बचा जाता है। कई अंतर्निहित संग्रह इस ट्रिक का उपयोग करते हैं, जैसे सूची । नोट: यह केवल तभी काम करेगा जब आपके पास इसका प्रत्यक्ष रेफ़रेंस होगा SingleSequence, जैसे आपके उदाहरण में। यदि आप इसे एक IEnumerable<>चर में संग्रहीत करते हैं तो चाल काम नहीं करेगी (इंटरफ़ेस विधि का उपयोग किया जाएगा)
hi 16:24

5

IanG के पास इस विषय पर एक अच्छी पोस्ट है , EnumerableFrom()नाम के रूप में सुझाव दिया गया है (और उल्लेख है कि हास्केल और आरएक्स इसे कहते हैं Return)। IIRC F # इसे रिटर्न भी कहता है । F # Seqके ऑपरेटर को कॉल करता हैsingleton<'T>

यदि आप C # -सेंट्रिक बनने के लिए तैयार हैं, तो इसे कॉल करना है Yield[ yield returnइसे साकार करने में शामिल होना]।

यदि आप इसके संपूर्ण पहलुओं में रुचि रखते हैं, तो जेम्स माइकल हरे के पास एक वापसी शून्य या एक आइटम पोस्ट भी है जो स्कैन के लायक है।


4

यह किसी भी बेहतर नहीं हो सकता है लेकिन यह अच्छा है:

Enumerable.Range(0, 1).Select(i => item);

यह। ये अलग है।
नवफाल

Ewww। यह एक बहुत विस्तार है, बस एक आइटम को एक enumerable में बदलने के लिए।
टूलमेकरसैट

1
यह नाश्ता बनाने के लिए रुब गोल्डबर्ग मशीन का उपयोग करने के बराबर है । हां यह काम करता है, लेकिन यह वहां पहुंचने के लिए 10 हुप्स के माध्यम से कूदता है। इस तरह की एक साधारण चीज लाखों बार निष्पादित होने वाले तंग लूप में किए जाने पर प्रदर्शन में अड़चन हो सकती है। व्यवहार में, प्रदर्शन का पहलू 99% मामलों में मायने नहीं रखता है, लेकिन व्यक्तिगत रूप से मुझे अभी भी लगता है कि यह सकल अनावश्यक ओवरकिल है।
enzi

4

मैं मूल पोस्ट में @ EarthEngine की टिप्पणियों से सहमत हूं, जो कि 'AsSingleton' एक बेहतर नाम है। इस विकिपीडिया प्रविष्टि को देखें । फिर यह सिंगलटन की परिभाषा से होता है कि यदि एक अशक्त मान को एक तर्क के रूप में पारित किया जाता है कि 'एसिंगलटन' को एक IEnumerable को खाली IEnumerable के बजाय वापस लौटना चाहिए जो if (item == null) yield break;बहस को सुलझाएगा । मुझे लगता है कि सबसे अच्छा समाधान दो तरीकों के लिए है: 'एससिंगटन' और 'एससिंगटनऑर्मी खाली'; जहाँ, इस स्थिति में कि एक अशक्त को तर्क के रूप में पारित किया जाता है, 'असिंगलटन' एक अशक्त मान लौटाएगा और 'एससिंगटनऑर्मी खाली' एक रिक्त IEnumerable लौटेगा। ऐशे ही:

public static IEnumerable<T> AsSingletonOrEmpty<T>(this T source)
{
    if (source == null)
    {
        yield break;
    }
    else
    {
        yield return source;
    }
}

public static IEnumerable<T> AsSingleton<T>(this T source)
{
    yield return source;
}

फिर, ये कम या ज्यादा, IEnumerable पर 'पहले' और 'FirstOrDefault' विस्तार विधियों के अनुरूप होंगे, जो कि सही लगता है।


2

सबसे आसान तरीका मैं कहूँगा new T[]{item};; ऐसा करने के लिए कोई सिंटैक्स नहीं है। निकटतम समतुल्य, जिसके बारे में मैं सोच सकता हूं params, वह कीवर्ड है, लेकिन निश्चित रूप से आपको विधि परिभाषा तक पहुंच की आवश्यकता है और केवल सरणियों के लिए उपयोग करने योग्य है।


2
Enumerable.Range(1,1).Select(_ => {
    //Do some stuff... side effects...
    return item;
});

जैसे उपयोग करते समय उपरोक्त कोड उपयोगी है

var existingOrNewObject = MyData.Where(myCondition)
       .Concat(Enumerable.Range(1,1).Select(_ => {
           //Create my object...
           return item;
       })).Take(1).First();

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


इस जवाब को स्वचालित रूप से "कम गुणवत्ता" का टैग दिया गया था। जैसा कि मदद में समझाया गया है ("ब्रेविटी स्वीकार्य है, लेकिन फुलर स्पष्टीकरण बेहतर हैं।"), कृपया ओपी को बताने के लिए इसे संपादित करें कि वह क्या गलत कर रहा है, आपका कोड क्या है।
सांद्रा रॉसी

मैं इस उत्तर के थोक को देखता हूं, जिसमें मैं जिस भाग का जवाब दे रहा हूं, उसे बाद में किसी अन्य व्यक्ति द्वारा संपादित किया गया था। लेकिन अगर दूसरा टुकड़ा के इरादे अगर एक डिफ़ॉल्ट मान प्रदान करने के लिए है MyData.Where(myCondition)खाली है, जो पहले से ही संभव (और सरल) के साथ है DefaultIfEmpty(): var existingOrNewObject = MyData.Where(myCondition).DefaultIfEmpty(defaultValue).First();var existingOrNewObject = MyData.FirstOrDefault(myCondition);यदि आप चाहते हैं default(T)और कस्टम मूल्य नहीं तो इसे और सरल बनाया जा सकता है ।
बेकन

0

मुझे पार्टी में थोड़ी देर हो गई है लेकिन मैं अपना रास्ता किसी भी तरह साझा करूँगा। मेरी समस्या यह थी कि मैं ItemSource या WPF TreeView को किसी एक ऑब्जेक्ट में बाँधना चाहता था। पदानुक्रम इस तरह दिखता है:

परियोजना> प्लॉट (ओं)> कक्ष (ओं)

हमेशा केवल एक परियोजना होने जा रही थी, लेकिन मैं अभी भी ट्री में इस परियोजना को दिखाना चाहता था, केवल एक संग्रह के साथ पारित करने के लिए, जिसमें कुछ सुझाव दिया गया था।
चूँकि आप केवल IEnumerable ऑब्जेक्ट को ही पारित कर सकते हैं, क्योंकि ItemSource के रूप में मैंने अपनी कक्षा को IEnumerable बनाने का निर्णय लिया:

public class ProjectClass : IEnumerable<ProjectClass>
{
    private readonly SingleItemEnumerator<AufmassProjekt> enumerator;

    ... 

    public IEnumerator<ProjectClass > GetEnumerator() => this.enumerator;

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

और उसी के अनुसार अपना Enumerator बनाएं:

public class SingleItemEnumerator : IEnumerator
{
    private bool hasMovedOnce;

    public SingleItemEnumerator(object current)
    {
        this.Current = current;
    }

    public bool MoveNext()
    {
        if (this.hasMovedOnce) return false;
        this.hasMovedOnce = true;
        return true;
    }

    public void Reset()
    { }

    public object Current { get; }
}

public class SingleItemEnumerator<T> : IEnumerator<T>
{
    private bool hasMovedOnce;

    public SingleItemEnumerator(T current)
    {
        this.Current = current;
    }

    public void Dispose() => (this.Current as IDisposable).Dispose();

    public bool MoveNext()
    {
        if (this.hasMovedOnce) return false;
        this.hasMovedOnce = true;
        return true;
    }

    public void Reset()
    { }

    public T Current { get; }

    object IEnumerator.Current => this.Current;
}

यह शायद "सबसे साफ" समाधान नहीं है, लेकिन यह मेरे लिए काम करता है।

EDIT एकल जिम्मेदारी सिद्धांत
को बनाए रखने के लिए @Groo ने बताया कि मैंने एक नया आवरण वर्ग बनाया है:

public class SingleItemWrapper : IEnumerable
{
    private readonly SingleItemEnumerator enumerator;

    public SingleItemWrapper(object item)
    {
        this.enumerator = new SingleItemEnumerator(item);
    }

    public object Item => this.enumerator.Current;

    public IEnumerator GetEnumerator() => this.enumerator;
}

public class SingleItemWrapper<T> : IEnumerable<T>
{
    private readonly SingleItemEnumerator<T> enumerator;

    public SingleItemWrapper(T item)
    {
        this.enumerator = new SingleItemEnumerator<T>(item);
    }

    public T Item => this.enumerator.Current;

    public IEnumerator<T> GetEnumerator() => this.enumerator;

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

जो मैंने इस तरह इस्तेमाल किया

TreeView.ItemSource = new SingleItemWrapper(itemToWrap);

EDIT 2
मैंने MoveNext()विधि के साथ एक गलती को सुधारा ।


SingleItemEnumerator<T>वर्ग समझ में आता है, लेकिन एक वर्ग एक "एक आइटम बनाने IEnumerableके ही" एकल जिम्मेदारी सिद्धांत का उल्लंघन की तरह लगता है। शायद यह इसे और अधिक व्यावहारिक के आसपास से गुजरता है, लेकिन मैं अभी भी इसे आवश्यकतानुसार लपेटना पसंद करूंगा।
Groo

0

के तहत दायर करने के लिए "जरूरी नहीं कि एक अच्छा समाधान है, लेकिन अभी भी ... एक समाधान" या "बेवकूफ LINQ चाल", आप के Enumerable.Empty<>()साथ गठबंधन कर सकते हैं Enumerable.Append<>()...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Append("Hello, World!");

... और Enumerable.Prepend<>()...

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Prepend("Hello, World!");

.NET फ्रेमवर्क 4.7.1 और .NET कोर 1.0 के बाद से बाद के दो तरीके उपलब्ध हैं।

यह एक व्यावहारिक समाधान है अगर कोई वास्तव में अपने स्वयं के लिखने के बजाय मौजूदा तरीकों का उपयोग करने पर आमादा था, हालांकि मैं इस मामले में Enumerable.Repeat<>()समाधान से अधिक या कम स्पष्ट हूं या नहीं । यह निश्चित रूप से लंबा कोड है (आंशिक रूप से टाइप पैरामीटर इंट्रेंस के कारण संभव नहीं हैEmpty<>() ) और दो बार एन्यूमरेटर ऑब्जेक्ट बनाता है, हालांकि।

इसे समाप्त करना "क्या आप जानते हैं कि ये विधियाँ मौजूद हैं?" उत्तर, Array.Empty<>()के लिए प्रतिस्थापित किया जा सकता है Enumerable.Empty<>(), लेकिन यह तर्क करना कठिन है कि स्थिति ... बेहतर है।


0

मैंने हाल ही में एक अन्य पोस्ट पर एक ही बात पूछी है ( क्या एक सी # विधि को कॉल करने का एक तरीका है, जिसमें एक मान के साथ IEnumerable <T> की आवश्यकता है? ... बेंचमार्किंग के साथ? )।

मैं चाहता था कि इन उत्तरों में प्रस्तुत दृष्टिकोणों में से 4 के लिए उस नई पोस्ट पर दिखाई गई संक्षिप्त बेंचमार्क तुलना को देखने के लिए लोग यहाँ रुकें।

ऐसा लगता है कि केवल new[] { x }विधि के तर्क में लिखना सबसे छोटा और सबसे तेज़ समाधान है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.