Что относительно SingleOrNew () метод вместо SingleOrDefault () в LINQ?

Objective-C имеет __attribute__((availability)) дольше, чем он имел @available. Чтобы заставить это работать, компилятор Objective C слабо связывает символы, которые не доступны в цели развертывания. Это означает, что компиляция всегда завершается успешно, а запуск вашего приложения успешен, но символ будет НЕДЕЙСТВИТЕЛЕН во время выполнения, если он недоступен.

В зависимости от того, что это такое, вы получите более или менее изящную деградацию, когда попытаетесь ее использовать:

  • вызов слабой связанной функции, которая отсутствует, приведет к сбою
  • чтение или запись в глобальную переменную, которая отсутствует, может привести к сбою
  • с использованием отсутствующего класса будет запретом, и все методы будут возвращать ноль

[ 1116] Старый способ проверить, найден ли символ во время выполнения, состоит в том, чтобы просто сравнить его с NULL:

NS_AVAILABLE_MAC(...) @interface Foo @end
int bar NS_AVAILABLE_MAC(...);
int baz(int frob) NS_AVAILABLE_MAC(...);

if ([Foo class]) { /* Foo is available */ }
if (&bar) { /* bar is available */ }
if (&baz) { /* baz is available */ }

В вашем случае:

Reader *tmp = [[Reader alloc] init];

tmp будет [ 115], потому что это будет то же самое, что и [[nil alloc] init].

Директива @available была добавлена ​​относительно недавно в Objective-C. Теперь можно использовать @available в Objective-C так же, как вы используете #available в Swift. Однако, чтобы сохранить обратную совместимость, возможно, никогда не будет ошибкой во время компиляции (при уровнях ошибок по умолчанию) пытаться использовать символ, который может быть недоступен для цели развертывания в Objective-C.

10
задан bdukes 18 February 2009 в 16:18
поделиться

6 ответов

Если все, что Вы хотите выполнить, должно переопределить значение по умолчанию (и возвратить новый объект), Вы можете делать так при помощи DefaultIfEmpty () Метод прежде, чем назвать SingleOrDefault (). Что-то как:

var client = db.Clients
    .Where(c => c.Name == name)
    .DefaultIfEmpty(new Client { Name = name })
    .SingleOrDefault();
9
ответ дан 3 December 2019 в 14:06
поделиться

Действительно, Вы просто хотите использовать пустой оператор объединения здесь. Пример:

var client = db.Clients
    .Where(c => c.Name == "Some Client")
    .SingleOrDefault() ?? new Client();

Это возвратит любые возвраты SingleOrDefault, за исключением того, что, если пустой указатель возвратов SingleOrDefault, выражение возвратит новый Клиент () вместо этого.

Править: Как John Skeet указал, это решение не дифференцируется между ситуацией, где там не идет ни в какое сравнение, и пустой элемент найден, хотя ясно это - не обязательно проблема во многих случаях. Альтернатива должна создать дополнительный метод следующим образом.

public static T SingleOrNew<T>(this IEnumerable<T> query) where T : new()
{
    try
    {
        return query.Single();
    }
    catch (InvalidOperationException)
    {
        return new T();
    }
}

Я сказал бы, что это - вероятно, самое изящное решение, которое работает в общем случае.

21
ответ дан 3 December 2019 в 14:06
поделиться

Это сделало бы? РЕДАКТИРОВАНИЕ Оказывается этим?? не будет работать с универсальным типом.

public static class IEnumerableExtensions
{
    public static T SingleOrNew<T>( this IEnumerable<T> query ) where T : new()
    {
        var value = query.SingleOrDefault();
        if (value == null)
        {
            value = new T();
        }
        return value;
    }
}
4
ответ дан 3 December 2019 в 14:06
поделиться

Кажется, что это могло быть сделано, да. Не может сказать, что я не забываю находиться в ситуации, где я использовал бы ее сам, но достаточно легко реализовать. Что-то вроде этого:

public static T SingleOrNew<T>(this IEnumerable<T> source) where T : new()
{
    if (source == null)
    {
        throw new ArgumentNullException("source"); 
    }
    using (IEnumerator<T> iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            return new T();
        }
        T first = iterator.Current;
        if (iterator.MoveNext())
        {
            throw new InvalidOperationException();
        }
        return first;
    }
}

Я добавлю его к списку операторов для включения в MoreLinq...

Другой, более общий подход должен был бы предоставить делегату, который будет только оценен при необходимости (мне нужно лучшее имя здесь, по общему признанию):

public static T SingleOrSpecifiedDefault<T>(this IEnumerable<T> source,
     Func<T> defaultSelector)
{
    if (source == null)
    {
        throw new ArgumentNullException("source"); 
    }
    if (defaultSelector == null)
    {
        throw new ArgumentNullException("defaultSelector"); 
    }
    using (IEnumerator<T> iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            return defaultSelector();
        }
        T first = iterator.Current;
        if (iterator.MoveNext())
        {
            throw new InvalidOperationException();
        }
        return first;
    }
}
2
ответ дан 3 December 2019 в 14:06
поделиться

Почему Вы не добавляете его с помощью Дополнительного метода затем? Кажется, что это было бы удобно.

1
ответ дан 3 December 2019 в 14:06
поделиться
var theClient =
    Repository<Client>
        .Entities()
        .Where(t => t.ShouldBeHere())
        .SingleOrDefault()
        ?? new Client { Name = "Howdy!" }
    ;
0
ответ дан 3 December 2019 в 14:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: