FirstOrDefault: अशक्त के अलावा अन्य डिफ़ॉल्ट मान


142

जैसा कि मैं इसे समझता हूं, लिनक में विधि शून्य के अलावा किसी और चीज का मूल्य FirstOrDefault()वापस कर सकती है Default। जब मैंने काम नहीं किया है, तो इस तरह की (और इसी तरह की) विधि द्वारा शून्य परिणाम के अलावा कोई आइटम नहीं होने पर किस तरह की चीजों को वापस किया जा सकता है। क्या कोई विशेष तरीका है कि इसे स्थापित किया जा सकता है ताकि यदि किसी विशेष क्वेरी के लिए कोई मूल्य न हो तो कुछ पूर्वनिर्धारित मूल्य को डिफ़ॉल्ट मान के रूप में लौटाया जाए?


147
इसके बजाय YourCollection.FirstOrDefault(), आप YourCollection.DefaultIfEmpty(YourDefault).First()उदाहरण के लिए उपयोग कर सकते हैं ।
स्लॉथ

6
मैं उपरोक्त टिप्पणी की तरह कुछ समय के लिए देख रहा हूँ, इसने काफी मदद की। यह स्वीकृत उत्तर होना चाहिए।
ब्रैंडन

उपरोक्त टिप्पणी सबसे अच्छा जवाब है।
टॉम पैडीला

मेरे मामले में @sloth का जवाब तब काम नहीं आया जब लौटाया गया मूल्य अशक्त है और एक अशक्त को सौंपा गया है। मैंने उसके लिए इस्तेमाल किया MyCollection.Last().GetValueOrDefault(0)। अन्यथा नीचे @Jon Skeet उत्तर IMO सही है।
Jnr

जवाबों:


46

सामान्य मामला, न केवल मूल्य प्रकारों के लिए:

static class ExtensionsThatWillAppearOnEverything
{
    public static T IfDefaultGiveMe<T>(this T value, T alternate)
    {
        if (value.Equals(default(T))) return alternate;
        return value;
    }
}

var result = query.FirstOrDefault().IfDefaultGiveMe(otherDefaultValue);

फिर, यह वास्तव में नहीं बता सकता है कि क्या आपके अनुक्रम में कुछ था , या यदि पहला मान डिफ़ॉल्ट था।

यदि आप इस बारे में परवाह करते हैं, तो आप कुछ ऐसा कर सकते हैं

static class ExtensionsThatWillAppearOnIEnumerables
{
    public static T FirstOr<T>(this IEnumerable<T> source, T alternate)
    {
        foreach(T t in source)
            return t;
        return alternate;
    }
}

और के रूप में उपयोग करें

var result = query.FirstOr(otherDefaultValue);

हालांकि जैसा कि श्री स्टेक बताते हैं कि यह अभी भी किया जा सकता है .DefaultIfEmpty(...).First()


आपके सामान्य तरीकों <T>को उनके नाम की आवश्यकता है, लेकिन अधिक गंभीर यह है कि value == default(T)काम नहीं करता है (क्योंकि कौन जानता है कि अगर Tसमानता के लिए तुलना की जा सकती है?)
आकाशवाणी

उस ओर इशारा करने के लिए धन्यवाद, @ आकाशवाणी; मैंने वास्तव में अब यह कोशिश की है और मुझे लगता है कि यह ठीक होना चाहिए (हालांकि मुझे मूल्य प्रकारों के लिए मुक्केबाजी पसंद नहीं है)।
रॉलिंग

3
@ रॉलिंग EqualityComparer<T>.Default.Equals(value, default(T))मुक्केबाजी से बचने के लिए उपयोग करें और यदि मान है तो एक अपवाद से बचेंnull
लुकाज़ोइड

199

जैसा कि मैंने इसे समझा, Linq में मेथड FirstOrDefault () null के अलावा किसी अन्य चीज़ का डिफ़ॉल्ट मान लौटा सकता है।

सं या इसके बजाय, यह हमेशा तत्व प्रकार के लिए डिफ़ॉल्ट मान लौटाता है ... जो या तो एक अशक्त संदर्भ है, एक अशक्त मान प्रकार का अशक्त मान, या गैर-अशक्त मूल्य प्रकार के लिए प्राकृतिक "सभी शून्य" मान।

क्या कोई विशेष तरीका है कि इसे स्थापित किया जा सकता है ताकि यदि किसी विशेष क्वेरी के लिए कोई मूल्य न हो तो कुछ पूर्वनिर्धारित मूल्य को डिफ़ॉल्ट मान के रूप में लौटाया जाए?

संदर्भ प्रकारों के लिए, आप उपयोग कर सकते हैं:

var result = query.FirstOrDefault() ?? otherDefaultValue;

बेशक यह आपको "अन्य डिफ़ॉल्ट मूल्य" भी देगा यदि पहला मूल्य मौजूद है, लेकिन एक अशक्त संदर्भ है ...


मुझे पता है कि प्रश्न संदर्भ प्रकार के लिए पूछता है, लेकिन आपके समाधान के लिए काम नहीं करता है जब तत्व मूल्य प्रकार होते हैं int। मैं बहुत का इस्तेमाल करते हैं DefaultIfEmpty: src.Where(filter).DefaultIfEmpty(defaultValue).First()। मूल्य प्रकार और संदर्भ प्रकार दोनों के लिए काम करता है।
KFL

@ केएफएल: गैर-अशक्त मूल्य प्रकारों के लिए, मैं शायद वह भी उपयोग करूंगा - लेकिन यह अशक्त मामलों के लिए अधिक लंबा-घुमावदार है।
जॉन स्कीट

डिफ़ॉल्ट होने पर वापसी के प्रकारों पर बहुत बढ़िया नियंत्रण .. :)
सुंदर प्रभू

"नहीं या बल्कि, यह हमेशा तत्व प्रकार के लिए डिफ़ॉल्ट मान लौटाता है ..." - यह मेरे लिए वास्तव में किया था .. जैसा कि मैंने फ़ंक्शन नाम का अर्थ भी गलत समझा है क्योंकि आप आवश्यक होने पर कोई डिफ़ॉल्ट मान प्रदान कर सकते हैं
जीसस कैंपोन

मुझे वास्तव में यह दृष्टिकोण पसंद आया, लेकिन मैंने "फंक <टी> वैकल्पिक" के साथ "टी वैकल्पिक" को बदल दिया, और फिर "वैकल्पिक वापसी ();" इस तरह जब तक मुझे ज़रूरत नहीं होती मैं अतिरिक्त वस्तु उत्पन्न नहीं करता। विशेष रूप से उपयोगी है यदि फ़ंक्शन को कई बार पंक्ति में कहा जाता है, तो निर्माता धीमा है या प्रकार का वैकल्पिक उदाहरण बहुत अधिक मेमोरी लेता है।
डेन वायलेट सैगमिलर

64

आप पहले के बाद DefaultIfEmpty का उपयोग कर सकते हैं :

T customDefault = ...;
IEnumerable<T> mySequence = ...;
mySequence.DefaultIfEmpty(customDefault).First();

मैं करने के विचार प्यार करता हूँ DefaultIfEmpty- यह सब एपीआई की जरूरत है कि एक डिफ़ॉल्ट निर्दिष्ट करने के साथ काम करता है: First(), Last(), आदि के लिए एक उपयोगकर्ता के रूप में, आप को याद है जो एपीआई डिफ़ॉल्ट जो नहीं है निर्दिष्ट कर सकते हैं की जरूरत नहीं है। बहुत खूबसूरत!
KFL

यह बहुत घोंसला उत्तर है।
जेसी विलियम्स

19

FirstOrDefault के लिए प्रलेखन से

[रिटर्न] डिफ़ॉल्ट (TSource) यदि स्रोत खाली है;

डिफ़ॉल्ट के लिए प्रलेखन से (टी) :

डिफ़ॉल्ट कीवर्ड, जो संदर्भ प्रकारों के लिए शून्य और संख्यात्मक मान प्रकारों के लिए शून्य होगा। संरचना के लिए, यह शून्य या शून्य के लिए आरंभिक संरचना के प्रत्येक सदस्य को इस आधार पर लौटाएगा कि वे मूल्य या संदर्भ प्रकार हैं। अशक्त मान प्रकारों के लिए, डिफ़ॉल्ट एक System.Nullable देता है, जिसे किसी भी संरचना की तरह आरंभीकृत किया जाता है।

इसलिए, डिफ़ॉल्ट मान शून्य या 0 हो सकता है जो इस बात पर निर्भर करता है कि प्रकार एक संदर्भ या मान प्रकार है, लेकिन आप डिफ़ॉल्ट व्यवहार को नियंत्रित नहीं कर सकते।


6

@Sloth की टिप्पणी से कॉपी किया गया

इसके बजाय YourCollection.FirstOrDefault(), आप YourCollection.DefaultIfEmpty(YourDefault).First()उदाहरण के लिए उपयोग कर सकते हैं ।

उदाहरण:

var viewModel = new CustomerDetailsViewModel
    {
            MainResidenceAddressSection = (MainResidenceAddressSection)addresses.DefaultIfEmpty(new MainResidenceAddressSection()).FirstOrDefault( o => o is MainResidenceAddressSection),
            RiskAddressSection = addresses.DefaultIfEmpty(new RiskAddressSection()).FirstOrDefault(o => !(o is MainResidenceAddressSection)),
    };

2
ध्यान दें कि DefaultIfEmptyडिफ़ॉल्ट लौटा है यदि संग्रह खाली है (जिसमें 0 आइटम हैं)। यदि आप Firstअपने उदाहरण में एक मिलान अभिव्यक्ति के साथ उपयोग करते हैं और उस स्थिति में कोई आइटम नहीं मिलता है तो आपका रिटर्न मान खाली हो जाएगा।
ओडोलबग

5

आप यह भी कर सकते हैं

    Band[] objects = { new Band { Name = "Iron Maiden" } };
    first = objects.Where(o => o.Name == "Slayer")
        .DefaultIfEmpty(new Band { Name = "Black Sabbath" })
        .FirstOrDefault();   // returns "Black Sabbath" 

यह केवल linq - yipee का उपयोग करता है!


2
इस उत्तर और विटामिन सी के उत्तर के बीच एकमात्र अंतर यह है कि यह एक FirstOrDefaultइसके बजाय का उपयोग करता है FirstMsdn.microsoft.com/en-us/library/bb340482.aspx के अनुसार , अनुशंसित उपयोग हैFirst
डैनियल

5

वास्तव में, NullReferenceExceptionजब मैं संग्रह के साथ काम कर रहा होता हूं तो बचने के लिए मैं दो दृष्टिकोणों का उपयोग करता हूं:

public class Foo
{
    public string Bar{get; set;}
}
void Main()
{
    var list = new List<Foo>();
    //before C# 6.0
    string barCSharp5 = list.DefaultIfEmpty(new Foo()).FirstOrDefault().Bar;
    //C# 6.0 or later
    var barCSharp6 = list.FirstOrDefault()?.Bar;
}

C # 6.0 या उसके बाद के लिए:

उपयोग करें ?.या ?[परीक्षण करें यदि कोई सदस्य पहुँच से पहले अशक्त है नल-सशर्त ऑपरेटर्स प्रलेखन

उदाहरण: var barCSharp6 = list.FirstOrDefault()?.Bar;

C # पुराना संस्करण:

DefaultIfEmpty()यदि अनुक्रम खाली है, तो एक डिफ़ॉल्ट मान प्राप्त करने के लिए उपयोग करें । MSDN प्रलेखन

उदाहरण: string barCSharp5 = list.DefaultIfEmpty(new Foo()).FirstOrDefault().Bar;


1
अशक्त प्रसार संचालक को अभिव्यक्ति वृक्ष लांबा में अनुमति नहीं है।
लार्स 335

1

इसके बजाय YourCollection.FirstOrDefault(), आप YourCollection.DefaultIfEmpty(YourDefault).First()उदाहरण के लिए उपयोग कर सकते हैं ।


जब आपको लगता है कि यह मददगार था, तो आप इसे बढ़ा सकते हैं। यह कोई उत्तर नहीं है।
jagagy02

1

मेरे पास बस ऐसी ही स्थिति थी और एक ऐसे समाधान की तलाश में थी जो मुझे हर बार मुझे कॉल करने वाले की तरफ ध्यान दिए बिना वैकल्पिक डिफ़ॉल्ट मान वापस करने की अनुमति दे। आमतौर पर हम जो करते हैं, लिनाक जो हम चाहते हैं उसका समर्थन नहीं करता है, एक नया विस्तार लिखना है जो इसकी देखभाल करता है। वही मैंने किया। यहाँ है कि मैं क्या साथ आया (हालांकि परीक्षण नहीं किया गया है):

public static class EnumerableExtensions
{
    public static T FirstOrDefault<T>(this IEnumerable<T> items, T defaultValue)
    {
        foreach (var item in items)
        {
            return item;
        }
        return defaultValue;
    }

    public static T FirstOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate, T defaultValue)
    {
        return items.Where(predicate).FirstOrDefault(defaultValue);
    }

    public static T LastOrDefault<T>(this IEnumerable<T> items, T defaultValue)
    {
        return items.Reverse().FirstOrDefault(defaultValue);
    }

    public static T LastOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate, T defaultValue)
    {
        return items.Where(predicate).LastOrDefault(defaultValue);
    }
}

0

मुझे पता है कि यह सबसे लोकप्रिय उत्तर के आधार पर थोड़ी देर के लिए है, लेकिन इल जोड़ रहा है, लेकिन थोड़ा विस्तार के साथ आईडी नीचे साझा करना पसंद है:

static class ExtensionsThatWillAppearOnIEnumerables
{
    public static T FirstOr<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> alternate)
    {
        var thing = source.FirstOrDefault(predicate);
        if (thing != null)
            return thing;
        return alternate();
    }
}

यह मुझे इस तरह के इनलाइन के रूप में कॉल करने की अनुमति देता है जैसे कि मेरे स्वयं के उदाहरण के साथ मुझे समस्या हो रही थी:

_controlDataResolvers.FirstOr(x => x.AppliesTo(item.Key), () => newDefaultResolver()).GetDataAsync(conn, item.ToList())

तो मेरे लिए मैं सिर्फ इनलाइन का उपयोग करने के लिए एक डिफ़ॉल्ट रिज़ॉल्वर चाहता था, मैं अपनी सामान्य जांच कर सकता हूं और फिर एक फ़ंक्शन में पास हो सकता हूं इसलिए अप्रयुक्त होने पर भी एक वर्ग को तत्काल नहीं दिया जाता है, इसके बजाय जब आवश्यक हो तो निष्पादित करने के लिए एक फ़ंक्शन!


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