Используйте .DefaultIfEmpty() вместо .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;

Ответы

Ответ 1

Вы можете использовать:

var query = ...;

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

Но это не уменьшает сложность IMO.

Ответ 2

Если вам интересен метод расширения, вы можете использовать что-то вроде этого:

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

Edit

Этот метод не является общим, потому что тогда нам нужно будет использовать default(T), и он даст нам null вместо string.Empty.

Ответ 3

Я нашел этот курс на PluralSight интересным, и я вспомнил его, когда увидел этот вопрос.

Вы можете посмотреть весь курс, но стратегии "Уменьшить карту" и Option<T>, особенно с DefaultIfEmpty, выглядели так, как будто это может быть хорошо подходит для вашего использования.

Тактические шаблоны проектирования в .NET: поток управления Зоран Хорват https://app.pluralsight.com/library/courses/tactical-design-patterns-dot-net-control-flow/table-of-contents

Ответ 4

Код:

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();

По подозрению в семантическом значении DefaultIfEmpty и FirstOrDefault следующий код декомпилируется из библиотеки:

  • Код

    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);
    }
    

И вот что можно сказать:

  • DefaultIfEmpty имеет безпараметрическую перегрузку, которая вызывает параметризованную перегрузку с помощью default(TSource) и возвращает ее результат.

  • Единственное различие между параметрами без параметров FirstOrDefault и First, которое будет выбрано последним, когда коллекция будет пуста.

    Для получения дополнительной информации см. Enumerable.FirstOrDefault <TSource> Метод в MSDN.

  • FirstOrDefault семантически выраженный first or default и так называемый; он не назван first or null. В С#, default(T) для ссылочного типа имеет значение null, но для типа без ссылки это не так. Например, default(int) равно нулю.

    Ключевое слово default никогда не указывалось семантически. Он ПО УМОЛЧАНИЮ.

    Кроме того, для получения дополнительной информации ключевое слово по умолчанию в MSDN.