마술 숫자보다 nullable 유형이 선호됩니까?


22

요즘 동료와 약간의 토론이있었습니다. 우리는 구체적으로 C #을 사용하고 있지만 이것은 nullable 타입을 가진 모든 언어에 적용될 수 있습니다. 예를 들어 최대 값을 나타내는 값이 있다고 가정하십시오. 그러나이 최대 값은 선택 사항입니다. 나는 nullable 숫자가 바람직하다고 주장한다. 내 동료는 선례를 인용하여 0을 사용하는 것을 선호합니다. 물론, 네트워크 소켓과 같은 것들은 종종 0을 사용하여 무제한 시간 초과를 나타냅니다. 오늘 소켓을 다루는 코드를 작성하려면 시간 초과가 없다는 사실을 더 잘 나타낼 것이라고 생각하기 때문에 개인적으로 nullable 값을 사용합니다.

어느 표현이 더 낫습니까? 둘 다 "없음"을 의미하는 값을 확인하는 조건이 필요하지만 nullable 유형은 의도를 조금 더 잘 전달한다고 생각합니다.


6
숫자가 사용되는 경우 코드에 직접 입력하지 않고 상수에 넣습니다.
Renato Dinhani 2016 년

@ RenatoDinhaniConceição 그것은 일반적인 규칙이 될 수 없습니다. 그렇지 않으면 모든 것이 소프트 코딩 됩니다.
Simon Bergot

답변:


24

치다:

  • 언어,

  • 뼈대,

  • 문맥.

1. 언어

∞를 사용하면 최대한의 해결책이 될 수 있습니다.

  • 예를 들어, JavaScript에는 무한대가 있습니다. C #은 ¹이 아닙니다.

  • 예를 들어 Ada에는 범위가 있습니다. C #은 그렇지 않습니다.

C #에는가 int.MaxValue있지만 귀하의 경우에는 사용할 수 없습니다. int.MaxValue최대 정수 2,147,483,647입니다. 코드에서 2,147,483,647을 사용하는 것은 폭발하기 전에 최대 허용 압력과 같이 최대 값을 가진 경우 의미가 없습니다.

2. 프레임 워크

.NET Framework는이 시점에서 다소 일관성이 없으며 마법 값의 사용을 비판 할 수 있습니다.

예를 들어, "Hello".IndexOf("Z")매직 값을 반환합니다 -1. 그것은 어쩌면 그것 (그것을합니까?) 쉽게 결과를 조작하기 위해 :

int position = "Hello".IndexOf("Z");
if (position > 0)
{
    DoSomething(position);
}

사용자 정의 구조를 사용하는 대신

SearchOccurrence occurrence = "Hello".IndexOf("Z");
if (occurrence.IsFound)
{
    DoSomething(occurrence.StartOffset);
}

그러나 전혀 직관적이지 않습니다. 왜 -1그렇지 -123않습니까? 초보자도 실수로 0"찾을 수 없음" 을 의미 한다고 생각 하거나 잘못 입력 할 수 있습니다.(position >= 0) .

3. 맥락

코드가 네트워크 소켓의 시간 초과와 관련이 있다면 일관성을 위해 수십 년 동안 모든 사람이 사용한 것을 사용하는 것은 나쁜 생각이 아닙니다 . 특히 0시간 초과가 매우 명확하다는 것은 0이 될 수없는 값입니다. 이 경우 사용자 정의 클래스를 사용하면 상황을 이해하기가 더 어려워 질 수 있습니다.

class Timeout
{
    // A value indicating whether there is a timeout.
    public bool IsTimeoutEnabled { get; set; }

    // The duration of the timeout, in milliseconds.
    public int Duration { get; set; }
}
  • 설정할 수 있습니까 DurationIsTimeoutEnabledtrue이면 0으로 ?
  • 경우 IsTimeoutEnabled거짓, 무엇을 내가 설정하면 어떻게Duration (100)에?

여러 실수가 발생할 수 있습니다. 다음 코드를 상상해보십시오.

this.currentOperation.Timeout = new Timeout
{
    // Set the timeout to 200 ms.; we don't want this operation to be longer than that.
    Duration = 200,
};

this.currentOperation.Run();

작업이 10 초 동안 실행됩니다. Timeout수업 문서를 읽지 않고이 코드의 문제점을 볼 수 있습니까 ?

결론

  • null여기에 가치가 없다는 아이디어를 잘 표현합니다. 제공되지 않습니다. 사용할 수 없습니다. 숫자도 아니고 0 / 빈 문자열도 아닙니다. 최대 값 또는 최소값으로 사용하지 마십시오.

  • int.MaxValue언어 자체와 밀접한 관련이 있습니다. 클래스 int.MaxValue의 최대 속도 제한 Vehicle또는 항공기 등의 최대 허용 속도 에는 사용하지 마십시오 .

  • -1코드에서 와 같이 마법의 값을 피하십시오 . 그들은 오도의 소지가 있으며 코드의 실수로 이어집니다.

  • 최소값 / 최대 값을 지정하여보다 직관적 인 클래스를 직접 만듭니다. 예를 VehicleSpeed들어을 가질 수 있습니다 VehicleSpeed.MaxValue.

  • 이 분야에서 코드를 작성하는 대부분의 사람들이 사용하는 매우 구체적인 분야에서 수십 년 동안 일반적인 관례라면 이전 지침을 따르지 않고 마법의 가치를 사용하십시오.

  • 접근 방식을 혼합하는 것을 잊지 마십시오. 예를 들면 다음과 같습니다.

    class DnsQuery
    {
        public const int NoTimeout = 0;
    
        public int Timeout { get; set; }
    }
    
    this.query.Timeout = 0; // For people who are familiar with timeouts set to zero.
    // or
    this.query.Timeout = DnsQuery.NoTimeout; // For other people.
    

¹ 무한대를 포함한 고유 한 유형을 만들 수 있습니다. 여기서는 기본 int유형에 대해서만 이야기하고 있습니다.


1
"일관되게하기 위해 수십 년 동안 모든 사람이 사용한 것을 사용하는 것은 나쁜 생각이 아닙니다." 대부분의 사람들은이 분야에서 코드를 작성합니다. " -어딘가에 오타가있는 것 같아요?
deworde

1
@deworde 나는 MainMa가 자신이 그 위에 준 지침을 언급하고 있다고 생각합니다.
Joshua Drake

1
-1이 문자열 외부에 있으므로 indexOf 예제에 동의하지 않습니다 .Z가 가장 확실합니다.
Joshua Drake

5
"예를 들어, 자바 스크립트는 무한대를 가지고 있습니다. C #은 그렇지 않습니다." - 응?
BlueRaja-대니 Pflughoeft

내가 제안했던 "나만의 수업 만들기"에 대해 +1 특히. 맨손으로 int문제를 제한하는 유형에 대해 충분히 표현하지 못할 때마다 더 많은 정보를 가진 새로운 구조체를 고려하십시오 (예를 들어 마법의 값을 나타내는 구조체의 const 인스턴스 또는이를 나타내는 열거 형). 또는 계약 프로그래밍 또는 다른 솔루션을 고려할 수 있지만 사용자 정의 구조체가 가장 간단하다고 생각합니다.
CodexArcanum

12

널은 마법의 숫자보다 낫지 않습니다.

중요한 것은 마법의 효과가있는 값의 이름을 지정하고 그러한 값을 가져야하는 경우 해당 값의 정의가 마법의 가치와 wtf에 부딪 치는 사람이 볼 수있는 곳인지 확인하는 것입니다.

if (timeout == 4298435) ... // bad.
if (timeout == null) ... // bad.
if (timeout == NEVER_TIME_OUT) ... // yay! puppies and unicorns!

2
좋아, 어쩌면 언어에 더 의존 할 수도 있지만 C #에서는 null과 직접 비교하는 대신 if (timeout.HasValue) 할 수 있습니다.
Matt H

2
Null은 매직 넘버보다 나쁘지 않습니다. 매직 넘버를 사용하면 매직 넘버가 무엇인지 알 수 없습니다. 0, -1 또는 다른 것이 될 수 있습니다. null은 단지 null입니다.
marco-fiset

9
Null은 가치가 없음을 의미합니다. 이것은 많은 마법 숫자가 표현하고자하는 개념입니다. 널 입력 가능 유형에 널을 사용할 수있는 것은 데이터 유형에 가능한 값 범위에서 임의의 값을 하나 선택하는 것보다 훨씬 나은 솔루션입니다.
17 of 26

2
유형에 "널"이 있으면 "널"을 마법의 값으로 사용하는 것이 좋습니다. 중요한 것은 NAME을 지정하는 것입니다. 다음에 올 사람을 쏠 때 당신이 무엇을 의미하는지 알 수 없기 때문입니다. 널은 "무한대", "아직 지정되지 않음", "데이터 구조를 작성한 코드의 버그"또는 기타 여러 가지를 의미 할 수 있습니다. 다음 코더는 이름 만 사용하여 해당 값이 존재한다는 의미와 트리거하려는 동작을 알 수 있습니다.
mjfgates

1
@ CodeInChaos : 둘 다 할 수 있다는 것을 알고 있지만 HasValue를 선호합니다. 나는 일반적으로 null의 큰 팬은 아니지만 HasValue를 사용하는 nullable 유형은 내가 팬인 Option / Maybe 유형에 조금 더 가깝습니다.
Matt H

10

MAGIC_NUMBER코드는 가능한 한 항상 피해야합니다. null보다 명확한 의도 표현입니다.


6

C #에서 많은 CLR 클래스에는 정적 Empty멤버가 있습니다.

  • System.String.Empty
  • System.EventArgs.Empty
  • System.Guid.Empty
  • System.Drawing.Rectangle.Empty
  • System.Windows.Size.Empty

이렇게하면 빈 객체를 생성하기 위해 매직 값을 사용할지 아니면 null을 사용할지를 기억하지 않아도됩니다.

그러나 간단한 값 유형을 다루는 경우 int? 이 경우, 원시 강박 관념에 희생되는지 여부를 고려하십시오 . 명백히 단순한 숫자 속성이 자체 클래스 또는 구조체의 이점을 얻을 수 있으므로 Empty멤버 를 지정하고 해당 종류의 값에 고유 한 다른 동작을 추가 할 수 있습니다 .


3

이 경우 널값은 최대 값이 없음을 나타내는 좋은 방법입니다. 일반적으로 특수한 경우에는 해당 값이 적용되지 않고 구성하는 기능을 원하지 않는 경우 null이 이에 대한 좋은 표시입니다.

특수한 경우를 나타내는 데 null을 사용할 때의 문제점은 하나의 null 값만 있고 여러 특수한 경우가있을 수 있다는 것입니다. 이 경우 특수한 경우를 나타내거나 int 값을 정상적으로 사용할 수있는 추가 매개 변수로 열거를 전달합니다. (이것은 본질적으로 Nullable <>이 당신을 위해하는 일이지만, 열거 형 대신 부울을 사용하고 매개 변수를 단일 구조로 결합합니다.)


3

이 경우 nullable 유형이 완벽하다고 생각합니다.

Null은 가치가 없음을 의미합니다. 이것은 값이 0 인 숫자와는 분명히 다른 개념입니다.

"값을 제공하지 않으면 최대 값을 사용하십시오"라고 말하고 싶다면 null을 전달하는 것이 정확한 표현 방법입니다.


1

널 (NULL) : 공통 오류 값, 지정되지 않음, 공백 또는 값 없음.

0 : 실제적이지만 반드시 논리적이거나 직관적 인 값은 아닙니다 (이 문맥에서). 초기화시 공통 값입니다.

문제의 맥락 timeoutInMilliseconds에서이 속성은 선택 사항이며이 방법의 오버 헤드로 인해 옵션으로 자격이 박탈 될 것이라는 언급은 없습니다.

결론 : 예외가 있으며 언어와 도메인에 따라 솔루션이 다릅니다. 이 경우 Null을 선택합니다. 일부 사람들 이이 잘못을 저지른 곳은 인터페이스와 데이터를 잘 분리하지 않은 경우입니다. 그들은 고객이 문서 (또는 구현)를 읽고 이러한 특수 값을 사용 / 처리하는 방법을 결정하기를 기대합니다. 특수 사례는 고객의 프로그램으로 유출되어 명확하지 않을 수 있습니다. 좋은 추상화 계층을 추가하면 사용법이 훨씬 명확해질 수 있습니다.


0

Null보다 사용하기가 좋지 않습니다 MagicNumber. 널 (Null)은 더 잘 표현 된 아이디어를 나타내지 만, 플랫폼에서 동작 방식이 일관성이 없으며 MagicNumber항상 같은 방식으로 작동하는 것이 유리합니다.

환경 / 언어에 따라 null을 사용할 수 있습니다.

  • 단순히 0
  • 법적 가치가 아닐 수 있습니다
  • 3 방향 논리로 인해 예기치 않은 결과가 발생할 수 있습니다

MagicNumber 항상 동일하게 동작합니다.


0

매직 넘버를 확인하는 것을 잊어 버린 경우 (올바로 진행됨), 넌센스가없는 데이터로 매직 넘버가 잠시 계속됩니다. 가능한 한 빨리 예외를 일으키는 null을 갖는 것이 좋습니다.


-1

Null이 마법 번호의 유일한 대안은 아닙니다.

public static int NO_TIMEOUT = 0;  // javaish

널은 악하다. 위의 예에서 코드는 분명히 null을 처리 할 수 ​​있으므로 도망 갈 수 있습니다. 그러나 일반적으로 null 전달을 시작하면 조만간 null 포인터 예외가 발생합니다. 코드를 처음 작성할 때 발생할 수는 없지만 코드는 첫 번째 릴리스보다 훨씬 오래 유지됩니다. 원래 개발자만큼 시스템에 대해 잘 모르는 사람들이 종종 유지 관리합니다.

스칼라는 예를 들어 Option 클래스에서 훌륭한 대안을 제공합니다. Option 클래스에는 두 가지 값 중 하나가 있습니다. 일부는 실제로 원하는 값을 래핑하고 없음은 값이 없습니다.

그것은 가치가 없을 수도 있고 더 나은 코드를 가지고 있다는 것을 모든 개발자에게 분명히합니다. 어쨌든 그것은 분명해야합니다.

그리고 모든 매직 넘버가 문제가되는 것은 아닙니다. 컨텍스트 0, 1, 1024 등에 따라 모두 명백 할 수 있습니다. 347? 네, 피해야 할 것입니다. :-)


4
-1 : "null is evil"를 정당화하십시오.
deworde

4
숫자의 별칭을 정의해도 여전히 마법의 숫자라는 사실은 바뀌지 않습니다.
17 of 26

글쎄, 아마도 당신은 내가하는 것과 다른 마법 수의 정의를 가지고있을 것입니다. en.wikipedia.org/wiki/…를
Jon Strayer

1
나는 Jon Strayer에 동의합니다. 널은 실제로 ADT를 지원하지 않는 언어로 된 ADT의 예입니다. OP는 아마도 여기서 벗어날 수 있지만 일반적으로 프로그래머가 약간 실패한 null이없는 언어를 고려합니다.
Jeremy Wall
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.