[C#] LINQ : 전혀 그렇지 않다

제공된 값이 목록의 값과 일치하는지 확인하려는 경우가 있습니다 (예 : 유효성 검사시).

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

최근 ReSharper가 다음과 같은 쿼리를 단순화하도록 요청했습니다.

if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}

분명히 이것은 논리적으로 동일하며 약간 더 읽기 쉽습니다 (많은 수학을 한 경우), 내 질문은 : 이것이 성능 저하를 초래합니까?

그것은 마치 느낌이 들지만 (즉 .Any(), 단락되는 .All()것처럼 들리지만 소리는 들리지 않습니다), 나는 이것을 입증 할 것이 없습니다. 쿼리를 통해 동일한 문제를 해결할지 또는 ReSharper가 나를 타락시키는 지에 대해 더 깊이 알고 있습니까?



답변

AllILSpy 에 따른 구현 (실제로 “잘, 그 방법은 약간 비슷하게 작동하는 것”보다는 실제로 갔다가 보았 기 때문에 영향보다는 이론을 논의하는 경우에 할 수있다).

public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    foreach (TSource current in source)
    {
        if (!predicate(current))
        {
            return false;
        }
    }
    return true;
}

AnyILSpy 에 따라 구현 :

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    foreach (TSource current in source)
    {
        if (predicate(current))
        {
            return true;
        }
    }
    return false;
}

물론, 생성 된 IL에는 약간의 미묘한 차이가있을 수 있습니다. 그러나 아닙니다. IL은 거의 동일하지만 술어 일치시 true를 리턴하는 것과 술어 불일치시 false를 리턴하는 것의 명백한 역전을 나타냅니다.

이것은 물론 linq-for-objects입니다. 다른 linq 제공자는 다른 linq 제공자가 다른 것보다 하나를 훨씬 잘 처리 할 수 ​​있지만,이 경우 더 최적의 구현을 가진 것은 무작위입니다.

이 규칙 if(determineSomethingTrue)은보다 단순하고 읽기 쉬운 사람에게만 적용되는 것 같습니다 if(!determineSomethingFalse). 그리고 공정성에서, 나는 그들이 if(!someTest)우리가 행동하고자하는 조건에 대해 진실로 되돌아 갈 수있는 동등한 상세 성과 복잡성에 대한 대안적인 테스트가있을 때 종종 혼란스러워 한다는 점을 생각 합니다. 그러나 실제로, 나는 개인적으로 당신이 제공하는 두 가지 대안 중 하나를 선호하는 것을 찾지 못하며, 술어가 더 복잡하다면 아마도 전자에게 약간 기울어 질 것입니다.

* 나는 이해하지 못하는 것처럼 혼란스럽지 않지만, 나는 이해하지 못하는 결정에 미묘한 이유가 있다고 걱정하고, “아니, 그들은 단지 그런 식으로 기다렸다가 다시이 코드를보고 있던 것이 무엇입니까? … “


답변

이러한 확장 방법을 사용하면 코드를 더 읽기 쉽게 만들 수 있습니다.

public static bool None<TSource>(this IEnumerable<TSource> source)
{
    return !source.Any();
}

public static bool None<TSource>(this IEnumerable<TSource> source,
                                 Func<TSource, bool> predicate)
{
    return !source.Any(predicate);
}

이제 원래 대신

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

넌 말할 수있다

if (acceptedValues.None(v => v == someValue))
{
    // exception logic
}


답변

– 둘 다 결과 후 모두 정지 열거 판단 할 수 있기 때문에 동일한 성능 것이다 Any()첫 번째 항목에 전달 된 술어 평가합니다로 trueAll()의 술어 평가하여 첫 번째 항목에를 false.


답변

All 첫 번째 비 일치에 단락이 발생하므로 문제가되지 않습니다.

미묘의 한 영역은

 bool allEven = Enumerable.Empty<int>().All(i => i % 2 == 0); 

사실이다. 시퀀스의 모든 항목이 균일합니다.

이 방법에 대한 자세한 내용은 Enumerable.All 설명서를 참조하십시오 .


답변

All()시퀀스의 모든 요소가 조건을 만족하는지 여부를 결정합니다.
Any()시퀀스의 요소가 조건을 만족하는지 여부를 결정합니다.

var numbers = new[]{1,2,3};

numbers.All(n => n % 2 == 0); // returns false
numbers.Any(n => n % 2 == 0); // returns true


답변

링크 에 따르면

모두 – 하나 이상의 일치를 확인합니다

모두 – 모두 일치하는지 확인


답변

다른 답변에서 잘 설명했듯이 성능에 관한 것이 아니라 명확성에 관한 것입니다.

두 옵션 모두에 대해 광범위하게 지원됩니다.

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}

그러나 이것이 더 광범위한 지원을 얻을 수 있다고 생각 합니다 .

var isValueAccepted = acceptedValues.Any(v => v == someValue);
if (!isValueAccepted)
{
    // exception logic
}

부울을 계산하기 전에 부울을 계산하고 이름을 지정하는 것만으로도 내 마음에 이것을 많이 알 수 있습니다.