IT

LINQ : 전혀 그렇지 않다

lottoking 2020. 3. 31. 08:27
반응형

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 제공자가 다른 것보다 하나를 더 잘 처리 할 수 ​​있지만,이 경우 더 최적의 구현을 가진 것은 무작위입니다.

It would seem that the rule comes down solely to someone feeling that if(determineSomethingTrue) is simpler and more readable than if(!determineSomethingFalse). And in fairness, I think they've a bit of a point in that I often find if(!someTest) confusing* when there's an alternative test of equal verbosity and complexity that would return true for the condition we want to act upon. Yet really, I personally find nothing to favour one over the other of the two alternatives you give, and would perhaps lean very slightly toward the former if the predicate were more complicated.

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


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

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
}

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


당신이 한 번 봐 걸릴 경우 Enumerable에서 소스 당신의 구현 것을 볼 수 AnyAll아주 가깝습니다 :

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 element in source) {
        if (predicate(element)) return true;
    }
    return false;
}

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 element in source) {
        if (!predicate(element)) return false;
    }
    return true;
}

유일한 차이점은 부울 부정에 속하기 때문에 한 방법이 다른 방법보다 훨씬 빠를 수있는 방법은 없으므로 잘못된 성능 승리보다 가독성을 선호합니다.

참고 URL : https://stackoverflow.com/questions/9027530/linq-not-any-vs-all-dont

반응형