삭제하도록 지정된 항목이 없으면 서비스에서 예외가 발생하거나 반환되어야 함


12

다음과 같이 나타낼 수있는 코드가 있습니다.

public class ItemService {

    public void DeleteItems(IEnumerable<Item> items)
    {
        // Save us from possible NullReferenceException below.
        if(items == null)
            return;

        foreach(var item in items)
        {
            // For the purpose of this example, lets say I have to iterate over them.
            // Go to database and delete them.
        }
    }
}

이제 이것이 올바른 접근법인지 또는 예외를 던져야하는지 궁금합니다. 반환은 빈 컬렉션을 반복하는 것과 동일하기 때문에 예외를 피할 수 있습니다. 즉, 중요한 코드는 실행되지 않지만 다른 한편으로는 코드의 어딘가에 문제가 숨어있을 수 있습니다. DeleteItemsnull매개 변수? 코드 어딘가에 문제가 있음을 나타낼 수 있습니다.

이것은 대부분 서비스에서 메소드와 관련하여 발생하는 문제입니다. 대부분이 무언가를하고 결과를 반환하지 않기 때문에 누군가가 잘못된 정보를 전달하면 서비스가 수행 할 작업이 없으므로 반환됩니다.


2
이것은 내 사람의 의견 일 뿐이지 만 의도하지 않은 (예외) 일을 할 때 메소드가 예외를 throw해야한다는 것이 가장 합리적이라고 생각했습니다. 귀하의 경우 누군가 누군가 null / 0 항목을 삭제하려고하면 InvalidOperationException이 발생합니다.
Falgantil


1
@gnat 내 질문은 서비스 사용법과 목적 때문에 서비스에 관한 것입니다. 이 "중복"은 일반적인 경우에 대해서만 이야기하며 주요 답변은 내 정확한 방법의 맥락에서 모순됩니다.
FCin

2
열거 형이 null 대신 비어있을 수 있습니까? 다르게 처리 하시겠습니까?
JAD

13
@Falgantil 나는 null이 예외에 합당하다는 것을 알 수 있지만 빈 목록에 예외를 던지는 것은 터무니없는 것이라고 생각합니다.
Kevin

답변:


58

이들은 두 가지 다른 질문입니다.

수락해야합니까 null? 그것은 null코드베이스 에 대한 일반적인 정책에 달려 있습니다 . 내 의견으로는, null명시 적으로 문서화 된 곳을 제외한 모든 곳 에서 금지 하는 것은 매우 좋은 습관이지만 코드베이스가 이미 가지고있는 규칙을 따르는 것이 더 좋습니다.

빈 컬렉션을 수락해야합니까? 제 생각에는 그렇습니다. 수학적으로 옳은 일을하는 것보다 모든 발신자를 비어 있지 않은 모음으로 제한하는 것이 훨씬 더 많은 노력입니다.


9
어쨌든 던질 예정이라면 AhaINoticedYouPassingInNullException런타임에 이미 NullReferenceException코드를 작성하지 않고도 던지기 기능을 제공 할 때 던지는 데 많은 유틸리티가 없습니다 . 몇 가지 유틸리티가 있습니다 (예 : 코드 커버리지 도구는 전자의 경우 null을 전달하기위한 단위 테스트가 있는지 여부를 알려주지 만 후자는 아님). 서비스를 호출 할 때마다 예외를 시도하거나 잡아서는 안됩니다. 일반적 으로 프로그래머 오류 이기 때문 입니다.
Steve Jessop

2
... 예상 한 매개 변수로 인해 예외가 발생하면 즉시 잡아야합니다. 일부 예상되는 경우 전달하는 것이 null이라는 것을 알고 호출하려는 함수가 적극적으로 유효성을 검사하려는 경우. 킬리안이 답변에서 밝힌 것처럼, 귀하의 일반적인 정책은 명시 적으로 허용되지 않은 곳에서는 null을 금지하는 것일 수 있습니다. 그럼 당신은 잡을 것 NullReferenceException또는 AhaINoticedYouPassingInNullException어디서든 높은 수준의 재해 복구 코드 제외. 그리고 예외 처리기는 아마도 버그 보고서를 만들어야합니다 :-)
Steve Jessop

2
@FCin : 인터페이스 디자인은 사용자가 실제로 서비스에서 필요로하지 않는 것과 일치해야합니다. 따라서 모든 발신자 가이 주위에 try / catch를 넣으려면이 방법이나 편리한 방법 중 하나가 null을 확인하고 무시해야합니다. 공개 요구이기 때문입니다. 그러나 Kilian이 말한 것처럼 일반적으로 전파 널을 프로그래밍 오류로 처리 하고 모든 호출 사이트에서 계속하려고 시도 하지 않는 것이 좋습니다. 이 문제를 해결하기 위해이 메소드를 호출하는 서비스 null가 컨트롤러에 포함되어 있습니까?
Steve Jessop

2
... 그렇다면 코드베이스가 누락 된 구성 요소를 지속적으로 낮은 수준에서 처리하고 계속 해야하는 예상 조건으로 처리하는 것처럼 보입니다. "이 작업을 진행할 수 있도록 서비스를 제공하고 열거 할 책임은 누구에게 있습니까?"라고 합리적으로 요청할 수 있습니다. 답변이 "누군가"인 경우 함수는 전제 조건을 확인 하고 있으며 전제 조건 실패의 결과는 일반적으로 모든 호출이 아닌 높은 수준에서 예외가 발생합니다. 작업에 필요한 항목이 실제로 선택 사항 인 경우 함수가 예상 사용 사례를 처리하는 것 입니다.
Steve Jessop

2
명시 적으로를 던지는 ArgumentNullException것이 내부 코드를 던지는 것보다 우수합니다 NullReferenceException.-예외 메시지를 보면 순수하게 던지기 사이트의 메소드 본문에서 논리 오류가 아니라 입력 오류라는 것이 분명합니다. 나중에 예기치 않은 널에서 부분적으로 변경되지 않고 다른 데이터를 유효한 상태로 두었을 가능성이 큽니다.
Miral

9

널값

@KilianFoth가 이미 말했듯이 일반적인 정책을 준수하십시오. null빈 목록의 "속기" 로 취급 하려면 그렇게하십시오.

null값 에 대한 일관된 정책이없는 경우 다음을 권장합니다.

null" null알 수 없음"을 나타내는 데 사용하는 등 "일반"유형으로 표현할 수없는 상황을 나타내도록 예약해야합니다 . 부주의하게이 값을 사용하려고하면 예외가 발생하므로 올바른 선택입니다.

null비어있는 목록의 속기로서 사용 하는 것은 이미 완벽한 표현이 있기 때문에 요소가없는 목록이기 때문에 그런 식으로 자격이 없습니다. 그리고 목록을 다루는 코드의 모든 부분이 유효한 속기를 검사하도록 강요하기 때문에 기술적으로 나쁜 선택 null입니다.

빈 목록

A의 DeleteItems()방법, 빈리스트를 건네 주면 효과적으로 아무것도하지 않는 것을 의미합니다. 나는 예외를 던지지 않고 단지 빨리 돌아 오는 것을 인수로 허용 할 것입니다.

물론, 호출자는 먼저 0 요소를 확인하고이 경우 DeleteItems()호출을 건너 뛸 수 있습니다. 우리가 웹 API에 대해 이야기하고 있다면, 효율성상의 이유로 호출자 실제로 불필요한 트래픽과 왕복 대기 시간을 피하기 위해 그렇게해야합니다. 그러나 나는 당신의 API가 그것을 강요해야한다고 생각하지 않습니다.


1

호출 코드에서 예외를 처리하고 널을 처리하십시오.

설계 규칙에 따라 매개 변수 값으로 null을 피하십시오. null은 실제로 예외이므로 일반적으로 NullPointerException을 줄입니다.

그 외에도 나머지 코드를 살펴보십시오. 이것이 프로젝트에서 일반적인 패턴 인 경우 일관성을 유지하십시오.


서비스 구성 방식을 "형성"하는 중이므로 잘못된 입력을 처리하기 위해 일부 리팩토링이 필요할 수 있지만 많이는 아닙니다. 그러나 null을 던지기 시작하면 null이 예외가 될 것이라는 점에 동의합니다.
FCin

0

일반적으로 예외 상황이 발생하는 경우 (예 : 코드에 현재 상황에서 취할 적절한 조치가없는 경우) 예외 발생을 예약해야합니다.

이 사고 과정을이 상황에 적용 할 수 있습니다. 이것이 공개 메소드가있는 공개 클래스이므로 공개 API가 있으며 이론적으로 전달되는 내용을 제어 할 수 없습니다.

코드에는 호출 대상에 대한 컨텍스트가 없으며 null 값으로 합리적으로 수행 할 수있는 작업이 없습니다. 이것은 확실히 후보가 될 것 ArgumentNullException입니다.


"코드에 현재 상황에서 취할 적절한 조치가없는 경우". 그러나 나의 생각은, 그것은 무효 행동을위한 합리적인 행동 과정을 가지고 있다는 것입니다. 빈 컬렉션을 전달할 때와 정확히 동일한 작업을 수행하므로 빈 컬렉션을 허용하면 왜 허용하지 않습니까 null?
FCin

1
@FCin 빈 컬렉션으로 인해 비어 있습니다. null당신 과 함께 컬렉션이 없습니다. 호출 코드가 메소드에 컬렉션을 제공한다고 가정 / 예상되는 경우 잘못된 것이 있으므로 던져야합니다. null을 빈 컬렉션과 동일하게 취급하는 유일한 이유는 호출 코드가 null 컬렉션을 생성 할 것으로 합리적으로 기대할 수 있기 때문입니다. 다른 답변에서 언급했듯이 대부분의 경우 무언가가 null이상합니다. 이것을 빈 컬렉션과 동일하게 취급하면 코드의 다른 곳에서 문제를 무시할 가능성이 있습니다.
JAD

@FCin : 또한 null비어 있음을 의미 한다면 이 방법에 따라 상황이 다릅니다. 동일한 코드 기반의 다른 곳에는 일종의 필터링을 수행 하는 IEnumerable또는 IContainer매개 변수가 있을 수 있으며 null"필터 없음"을 의미 할 수 있지만 (모든 것을 허용 함) 빈 필터는 아무것도 허용하지 않습니다. 그리고 다른 곳에서는 null"알지 못한다"는 것을 의미 할 수 있습니다. 따라서 null그것이 모든 곳에서 항상 똑같은 것을 의미 하는 것은 아니며, 그 의미가 필요하거나 적어도 누군가에게 유용하지 않으면 전혀 의미를 발명하지 않는 것이 좋습니다.
Steve Jessop

0

이 질문은 예외에 관한 것이 아니라 null유효한 논증 에 관한 것 같습니다 .

따라서 무엇보다도 null해당 메소드의 인수에 허용되는 값 인지 여부를 결정 해야합니다. 그렇다면 예외가 필요하지 않습니다. 그렇지 않은 경우 예외가 필요합니다.

당신이 허용하든 원하지 않든간에 null많은 구글 히트에 의해 논란의 여지가 있습니다. 의미, 당신은 명확한 대답을 얻을 수 없습니다, 그것은 당신이 일하는 곳에서 의견과 전통에 다소 달려 있습니다.

또 다른 경합 영역은 라이브러리 함수가 잘못된 매개 변수를 "고정"하려고하지 않는 한 그러한 것들에 대해 실제로 엄격 해야하는지 아니면 가능한 한 관대 해야하는지 입니다. 이것을 네트워크 프로토콜, 메일 전송 등 (프로그래밍 방법과 같은 인터페이스 계약)의 세계와 비교하십시오. 일반적으로 정책은 발신자가 프로토콜을 최대한 엄격하게 준수해야하며 수신자는 어떤 상황에서도 작업 할 수 있도록해야합니다.

따라서 결정해야합니다. 실제로 null처리 와 같은 대규모 정책을 시행하는 것이 라이브러리 방법의 역할 입니까? 특히 도서관이 다른 사람들도 사용하는 경우 (다른 정책이있을 수 있음).

나는 null값 을 허용 하고, 의미를 정의하고 문서화하는 (즉, null = empty array이 경우) 측면에서 실수를 저지르고 다른 유사한 코드 ( "라이브러리"스타일 코드)의 99 %가 다른 방식으로 수행하지 않는 한 예외를 throw 하지 않을 것입니다 '일주.


1
"널 처리와 같은 다소 큰 정책을 시행하는 것이 실제로 라이브러리 방법의 일인가?" 이러한 사고 방식은 주장과 디버그 모드로, 정책을 실제로 시행하는 대신 정책을 시행하는 데 도움 수 있습니다 . 따라서 당신이 null받아들이는 것에서 자유주의라는 원칙 을 삼키려고한다면 , 벌목이나 던지기는 의도 가 엄격한 사람들 이지만, 코드를 엉망 으로 만든 사람들에게 도움이 될 것입니다. 그들의 단위 테스트는 null어쨌든 통과 합니다.
Steve Jessop

@SteveJessop, 나는 당신이 내 대답의 정신에 반박하는지, 또는 당신이 그 선을 계속하고 있는지 여부를 정말로 모른다. 즉, 나는 단순히 삼키는 null것이 아니라 메서드의 계약에서 그것을 받아 들일 수 있는지 (또는 OP가 나오는 솔루션에 따라 다름) 공개를 선언 한 다음 예외를 던질 지 여부에 대한 질문입니다. (또는) 자신을 해결합니다.
AnoE
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.