簡體   English   中英

使用 .DefaultIfEmpty() 而不是 .FirstOrDefault() ?? String.Empty;

[英]Use .DefaultIfEmpty() instead of .FirstOrDefault() ?? String.Empty;

如何集成.DefaultIfEmpty()擴展方法,以便我不必使用

.FirstOrDefault() ?? String.Empty;

代碼:

(from role in roleList
let roleArray = role.RoleId.Split(new char[] { WorkflowConstants.WorkflowRoleDelimiter })
where roleArray.Length.Equals(_SplittedRoleIdArrayLength) && 
      HasAccessToCurrentUnit(roleArray[_UnitIndexInRoleId])
select roleArray[_LevelIndexInRoleId]).FirstOrDefault() ?? String.Empty;

你可以使用:

var query = ...;

return query.DefaultIfEmpty(string.Empty).First();

但這並沒有降低IMO的復雜性。

如果您對擴展方法感興趣,那么您可以使用以下內容:

public static class Helpers
{
    public static string FirstOrEmpty(this IEnumerable<string> source)
    {
        return source.FirstOrDefault() ?? string.Empty;
    }
}

編輯

這個方法不是通用的,因為那時我們必須使用default(T) ,它會給我們null而不是string.Empty

我發現這個關於PluralSight的課程很有趣,當我看到這個問題時我記得它。

您可以觀看整個過程,但Map Reduce和Option<T>策略尤其是使用DefaultIfEmpty似乎可能非常適合您的用例。

.NET中的戰術設計模式:Zoran Horvat的控制流程 https://app.pluralsight.com/library/courses/tactical-design-patterns-dot-net-control-flow/table-of-contents

編碼:

var query=(
    from role in roleList
    let delimiter=WorkflowConstants.WorkflowRoleDelimiter
    let roleArray=role.RoleId.Split(new char[] { delimiter })
    where roleArray.Length.Equals(_SplittedRoleIdArrayLength)
    where HasAccessToCurrentUnit(roleArray[_UnitIndexInRoleId])
    select roleArray[_LevelIndexInRoleId]
    ).DefaultIfEmpty("").FirstOrDefault();

由於懷疑DefaultIfEmptyFirstOrDefault的語義含義,以下是從庫反編譯的代碼:

  •  public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source) { return source.DefaultIfEmpty<TSource>(default(TSource)); } public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue) { if (source == null) { throw Error.ArgumentNull("source"); } return DefaultIfEmptyIterator<TSource>(source, defaultValue); } public static TSource First<TSource>(this IEnumerable<TSource> source) { if (source == null) { throw Error.ArgumentNull("source"); } IList<TSource> list = source as IList<TSource>; if (list != null) { if (list.Count > 0) { return list[0]; } } else { using (IEnumerator<TSource> enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { return enumerator.Current; } } } throw Error.NoElements(); } public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) { if (source == null) { throw Error.ArgumentNull("source"); } IList<TSource> list = source as IList<TSource>; if (list != null) { if (list.Count > 0) { return list[0]; } } else { using (IEnumerator<TSource> enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { return enumerator.Current; } } } return default(TSource); } 

這里有一點需要提及:

  1. DefaultIfEmpty具有無參數重載,它使用default(TSource)調用參數化重載並返回其結果。

  2. 無參數FirstOrDefaultFirst之間的唯一區別是后者在集合為空時拋出。

    有關更多信息,請參閱MSDN上的Enumerable.FirstOrDefault <TSource>方法

  3. FirstOrDefault語義表達為first or default ,因此被稱為; 它沒有被命名為first or null 在c#中,引用類型的default(T)null ,但對於非引用類型,則不是。 例如, default(int)為零。

    關鍵字default在語義上從未說過null 這是默認的

    此外,有關更多信息,請在MSDN上使用默認關鍵字

.NET 6 引入了能夠傳入默認值應該是什么的概念,如果沒有找到該項目。 例如,此代碼現在在 .NET 6 中有效:

source.FirstOrDefault(String.Empty);

或者:

List<int> numbers = new List<int>();
var custom = numbers.FirstOrDefault(-1);

在上面的例子中,我們不再需要依賴於返回 0,這是 int 的默認值。 當 0 是使用數字列表的上下文中的有效數字時,這可能很方便,而 -1 不是。

你可以閱讀更多:

https://dotnetcoretutorials.com/2021/09/02/linq-ordefault-enhancements-in-net-6/ https://adamstorr.azurewebsites.net/blog/default-your-firstordefault-in-net6.0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM