एक छोटी राशि कोड में एक बार करने के मामले में सबसे साफ, जैसा कि पहले ही उल्लेख किया गया है:
decimal result = (from Item itm in itemList
where itm.Amount > 0
select itm.Amount).DefaultIfEmpty().Min();
कास्टिंग के साथ itm.Amountकरने के लिए decimal?और प्राप्त करने Minकि के neatest जा रहा है अगर हम इस खाली हालत पता लगाने में सक्षम होना चाहता हूँ।
हालांकि अगर आप वास्तव में प्रदान करना चाहते हैं MinOrDefault()तो हम निश्चित रूप से शुरू कर सकते हैं:
public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source, TSource defaultValue)
{
return source.DefaultIfEmpty(defaultValue).Min();
}
public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source)
{
return source.DefaultIfEmpty(defaultValue).Min();
}
public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TSource defaultValue)
{
return source.DefaultIfEmpty(defaultValue).Min(selector);
}
public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
{
return source.DefaultIfEmpty().Min(selector);
}
अब आपके पास एक MinOrDefaultचयनकर्ता शामिल है या नहीं, और क्या आप डिफ़ॉल्ट निर्दिष्ट करते हैं या नहीं, इसका एक पूरा सेट है ।
इस बिंदु पर आपके कोड से बस:
decimal result = (from Item itm in itemList
where itm.Amount > 0
select itm.Amount).MinOrDefault();
इसलिए, जबकि शुरू करने के लिए यह उतना साफ नहीं है, यह तब से नीच है।
लेकिन रुकें! अभी और है!
मान लीजिए कि आप EF का उपयोग करते हैं और asyncसमर्थन का उपयोग करना चाहते हैं । आसानी से किया:
public static Task<TSource> MinOrDefaultAsync<TSource>(this IQueryable<TSource> source, TSource defaultValue)
{
return source.DefaultIfEmpty(defaultValue).MinAsync();
}
public static Task<TSource> MinOrDefaultAsync<TSource>(this IQueryable<TSource> source)
{
return source.DefaultIfEmpty(defaultValue).MinAsync();
}
public static Task<TSource> MinOrDefaultAsync<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TSource defaultValue)
{
return source.DefaultIfEmpty(defaultValue).MinAsync(selector);
}
public static Task<TSource> MinOrDefaultAsync<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
{
return source.DefaultIfEmpty().MinAsync(selector);
}
(ध्यान दें कि मैं awaitयहां उपयोग नहीं करता हूं ; हम सीधे एक Task<TSource>ऐसा बना सकते हैं जो हमें इसके बिना की आवश्यकता है, और इसलिए छिपी हुई जटिलताओं से awaitबचाता है)।
लेकिन रुकिए, और भी है! मान लें कि हम IEnumerable<T>कुछ समय के साथ इसका उपयोग कर रहे हैं । हमारा दृष्टिकोण उप-इष्टतम है। निश्चित रूप से हम बेहतर कर सकते हैं!
सबसे पहले, Minपर परिभाषित int?, long?, float? double?और decimal?पहले से ही क्या हम वैसे भी चाहते हैं (मार्क Gravell का जवाब बनाता है के उपयोग के रूप में) है। इसी तरह, हमें वह व्यवहार भी मिलता है जिसे हम Minपहले से परिभाषित चाहते हैं यदि किसी अन्य के लिए कहा जाता हैT? । तो चलो कुछ छोटे, और इसलिए आसानी से इनलाइन, इस तथ्य का लाभ उठाने के तरीके:
public static TSource? MinOrDefault<TSource>(this IEnumerable<TSource?> source, TSource? defaultValue) where TSource : struct
{
return source.Min() ?? defaultValue;
}
public static TSource? MinOrDefault<TSource>(this IEnumerable<TSource?> source) where TSource : struct
{
return source.Min();
}
public static TResult? Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult?> selector, TResult? defaultValue) where TResult : struct
{
return source.Min(selector) ?? defaultValue;
}
public static TResult? Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult?> selector) where TResult : struct
{
return source.Min(selector);
}
अब पहले अधिक सामान्य मामले से शुरू करते हैं:
public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
{
if(default(TSource) == null)
{
var result = source.Min();
return result == null ? defaultValue : result;
}
else
{
var comparer = Comparer<TSource>.Default;
using(var en = source.GetEnumerator())
if(en.MoveNext())
{
var currentMin = en.Current;
while(en.MoveNext())
{
var current = en.Current;
if(comparer.Compare(current, currentMin) < 0)
currentMin = current;
}
return currentMin;
}
}
return defaultValue;
}
अब स्पष्ट ओवरराइड जो इसका उपयोग करते हैं:
public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source)
{
var defaultValue = default(TSource);
return defaultValue == null ? source.Min() : source.MinOrDefault(defaultValue);
}
public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue)
{
return source.Select(selector).MinOrDefault(defaultValue);
}
public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
return source.Select(selector).MinOrDefault();
}
यदि हम प्रदर्शन के बारे में वास्तव में तेज हैं, तो हम कुछ मामलों के लिए अनुकूलन कर सकते हैं, जैसे Enumerable.Min()कि:
public static int MinOrDefault(this IEnumerable<int> source, int defaultValue)
{
using(var en = source.GetEnumerator())
if(en.MoveNext())
{
var currentMin = en.Current;
while(en.MoveNext())
{
var current = en.Current;
if(current < currentMin)
currentMin = current;
}
return currentMin;
}
return defaultValue;
}
public static int MinOrDefault(this IEnumerable<int> source)
{
return source.MinOrDefault(0);
}
public static int MinOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector, int defaultValue)
{
return source.Select(selector).MinOrDefault(defaultValue);
}
public static int MinOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
{
return source.Select(selector).MinOrDefault();
}
और के लिए पर इसलिए long, float, doubleऔर decimalके सेट से मेल करने के Min()द्वारा उपलब्ध कराई गई Enumerable। यह उस प्रकार की चीज़ है जहाँ T4 टेम्प्लेट उपयोगी हैं।
इन सभी के अंत में, हमारे पास बस उसी प्रकार के कार्यान्वयन के बारे में है MinOrDefault(), जिस प्रकार की एक विस्तृत श्रृंखला के लिए हम आशा कर सकते हैं। निश्चित रूप से इसके लिए एक उपयोग के चेहरे में "साफ" नहीं (फिर से, बस उपयोग करें DefaultIfEmpty().Min()), लेकिन बहुत अधिक "साफ" अगर हम खुद को इसका उपयोग करते हुए पाते हैं, तो हमारे पास एक अच्छा पुस्तकालय है जिसे हम पुन: उपयोग (या वास्तव में, पेस्ट कर सकते हैं) StackOverflow… पर उत्तर)।