문제

작업 중인 개체에 연결된 다른 개체 컬렉션이 있다고 상상해 보세요(예: WinForm의 Controls 컬렉션).컬렉션의 특정 개체를 확인하고 싶지만 컬렉션에 Contains() 방법.이를 처리하는 방법에는 여러 가지가 있습니다.

  • 자신만의 구현 Contains() 컬렉션의 모든 항목을 반복하여 그 중 하나가 찾고 있는 항목인지 확인하는 방법입니다.이것이 "모범 사례" 접근 방식인 것 같습니다.
  • 최근에 루프 대신 다음과 같이 try 문 내부의 개체에 액세스하려는 시도가 있는 일부 코드를 발견했습니다.
try  
{  
    Object aObject = myCollection[myObject];  
}  
catch(Exception e)  
{  
    //if this is thrown, then the object doesn't exist in the collection
}

내 질문은 두 번째 옵션이 얼마나 열악한 프로그래밍 관행이라고 생각하며 그 이유는 무엇입니까?컬렉션을 통한 루프와 비교하면 성능이 어떻습니까?

도움이 되었습니까?

해결책

나는 이것이 꽤 나쁜 습관이라고 말하고 싶습니다.일부 사람들은 컬렉션을 반복하는 것이 예외를 발생시키는 것보다 덜 효율적이라고 기꺼이 말할 수도 있지만, 예외를 발생시키는 데에는 오버헤드가 있습니다.또한 사전이나 해시테이블을 사용하는 것이 더 적합할 때 키로 항목에 액세스하기 위해 컬렉션을 사용하는 이유에 대해서도 질문하고 싶습니다.

그러나 이 코드의 주요 문제점은 발생한 예외 유형에 관계없이 항상 동일한 결과가 남게 된다는 것입니다.

예를 들어 개체가 컬렉션에 존재하지 않거나 컬렉션 자체가 null이거나 myCollect[myObject]를 aObject로 캐스팅할 수 없기 때문에 예외가 발생할 수 있습니다.

이러한 모든 예외는 동일한 방식으로 처리되지만 이는 의도한 것이 아닐 수도 있습니다.

다음은 예외를 발생시키는 것이 일반적으로 허용되는 시기와 위치에 대한 몇 가지 유용한 기사입니다.

나는 특히 두 번째 기사의 다음 인용문을 좋아합니다.

예상치 못한 또는 유효하지 않은 활동이 발생하는 경우에만 예외가 발생하는 것이 중요합니다.예외 처리는 작은 오버 헤드를 소개하고 성능을 낮추므로 조건부 처리 대신 일반 프로그램 흐름에 사용해서는 안됩니다.또한 이런 식으로 예외 처리를 잘못 사용하는 코드를 유지하기가 어려울 수 있습니다.

다른 팁

일반적인 경험 법칙은 예외를 유발하는 상황이 "예외"인 경우(예: 극히 드문 경우)가 아닌 이상 제어 흐름에 예외를 사용하지 않는 것입니다.

이것이 정상적으로 정기적으로 발생하는 경우에는 예외로 처리되어서는 안 됩니다.

관련된 모든 오버헤드로 인해 예외가 매우 느립니다. 따라서 예외가 자주 발생한다면 성능상의 이유도 있을 수 있습니다.

코드를 작성하는 동안 이 개체가 컬렉션에 있을 것으로 예상했는데 런타임 중에 컬렉션에 포함되어 있지 않다는 사실을 알게 되면 이를 예외 사례라고 부르며 예외를 사용하는 것이 적절합니다.

그러나 단순히 객체의 존재 여부를 테스트하고 객체가 존재하지 않는 경우에도 예외는 아닙니다.이 경우 예외를 사용하는 것은 적절하지 않습니다.

런타임 성능 분석은 사용되는 실제 컬렉션과 이를 검색하는 방법에 따라 달라집니다.그래도 그건 중요하지 않습니다.최적화라는 환상에 속아서 혼란스러운 코드를 작성하지 마십시오.

내가 얼마나 좋아하는지 좀 더 생각해봐야 할 것 같은데...내 직감은, 어, 별로...

편집하다:예외적인 경우에 대한 Ryan Fox의 의견은 완벽합니다. 동의합니다.

성능은 컬렉션의 인덱서에 따라 다릅니다.C#을 사용하면 인덱서 연산자를 재정의할 수 있으므로 작성하는 포함 메서드와 같은 for 루프를 수행하는 경우 속도가 느려집니다(try/catch로 인해 몇 나노초 정도 느려질 수 있음).하지만 해당 코드 자체가 거대한 루프 내에 있지 않는 한 걱정할 필요가 없습니다.

인덱서가 O(1)(또는 심지어 O(log(n))인 경우...또는 O(n)보다 빠른 것), try/catch 솔루션은 물론 더 빠릅니다.

또한 인덱서가 예외를 발생시키고 있다고 가정합니다. 예외가 null을 반환하는 경우에는 물론 null을 확인하고 try/catch를 사용하지 않을 수도 있습니다.

일반적으로 프로그램 흐름과 논리에 예외 처리를 사용하는 것은 나쁜 습관입니다.나는 개인적으로 후자의 선택이 허용되지 않는 예외 사용이라고 생각합니다.요즘 일반적으로 사용되는 언어의 기능(예: C#의 Linq 및 람다)을 고려하면 자체 Contains() 메서드를 작성하지 않을 이유가 없습니다.

마지막으로 요즘 대부분의 컬렉션은 하다 이미 포함 메소드가 있습니다.그래서 저는 이것이 대부분 문제가 되지 않는다고 생각합니다.

예외는 예외적이어야 합니다.

'데이터베이스가 아래에서 떨어져서 컬렉션이 누락되었습니다.'와 같은 것은 예외적입니다.

'키가 없습니다'와 같은 것은 사전의 정상적인 동작입니다.

winforms Control 컬렉션의 특정 예를 보려면 Controls 부동산에는 ContainsKey 당신이 사용해야하는 방법입니다.

없다 ContainsValue 왜냐하면 사전/해시테이블을 다룰 때 전체 컬렉션을 반복하고 무언가가 있는지 확인하는 것 외에는 빠른 방법이 없기 때문에 실제로 그렇게 하는 것은 낙담합니다.

예외가 예외적이어야 하는 이유는 대략 2가지입니다.

  1. 코드가 수행하려는 작업을 나타냅니다.코드가 달성하려는 목표와 최대한 일치하도록 하여 읽기 쉽고 유지 관리가 가능하도록 하려고 합니다.예외 처리는 이 목적을 방해하는 추가적인 잔해물을 추가합니다.

  2. 코드의 간결함.코드가 수행하는 작업을 가장 직접적인 방식으로 수행하여 읽기 쉽고 유지 관리가 가능해지기를 원합니다.다시 말하지만, 예외 처리로 인해 추가된 잡동사니가 이를 방해합니다.

Krzystof의 다음 블로그 게시물을 살펴보세요. http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

예외는 오류 조건을 전달하는 데 사용해야 하지만 제어 논리로 사용해서는 안 됩니다(특히 포함과 같이 조건을 결정하는 훨씬 간단한 방법이 있는 경우).

문제의 일부는 예외가 있지만 비용이 많이 들지 않는다는 것입니다. 던지다 비싸다 잡다 모든 예외는 어느 시점에서 포착됩니다.

후자는 허용 가능한 솔루션입니다.이 경우 컬렉션에서 발생하는 특정 예외(ElementNotFound?)를 확실히 포착할 수는 있습니다.

속도는 일반적인 경우에 따라 다릅니다.요소를 찾지 못할 가능성보다 찾을 가능성이 더 높으면 예외 솔루션이 더 빨라집니다.실패할 가능성이 더 높다면 컬렉션의 크기와 반복 속도에 따라 달라집니다.어느 쪽이든, 이와 같은 속도에 대해 걱정하기 전에 이것이 실제로 병목 현상인지 확인하기 위해 일반적인 사용과 비교하여 측정하고 싶을 것입니다.먼저 명확성을 추구하면 후자의 솔루션이 전자보다 훨씬 더 명확해집니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top