C #에서 Guid.Empty로 매개 변수를 기본값으로 설정하는 방법은 무엇입니까?


178

나는 말하고 싶다 :

public void Problem(Guid optional = Guid.Empty)
{
}

그러나 컴파일러는 Guid.Empty가 컴파일 시간 상수가 아니라고 불평합니다.

API를 변경하고 싶지 않으므로 사용할 수 없습니다.

 Nullable<Guid>


로 전환하면 Nullable<Guid> optional = null(또는 더 심하게 Guid? optional = null) 무엇이 잘못 되었습니까? 현재 전달 된 모든 Guid는 코드를 전혀 변경하지 않아도 강제됩니다.
NH.

답변:


235

해결책

new Guid()대신 사용할 수 있습니다

public void Problem(Guid optional = new Guid())
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

당신은 또한 사용할 수 있습니다 default(Guid)

default(Guid) 또한 정확히 작동합니다 new Guid() .

Guid는 참조 유형이 아닌 값 유형이므로 default(Guid)같지 않습니다.null 예를 들어, 대신, 그것은 기본 생성자를 호출 동일합니다.

이는 다음을 의미합니다.

public void Problem(Guid optional = default(Guid))
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

원래 예제와 정확히 동일합니다.

설명

왜 안했어 Guid.Empty 작동 않습니까?

오류가 발생하는 이유 Empty는 다음과 같이 정의 되기 때문 입니다.

public static readonly Guid Empty;

그래서, 그것은으로 정의 된 변수가 아닌 상수 (인 static readonly하지가const ). 컴파일러는 컴파일러에서 알려진 값만 메소드 매개 변수 기본값으로 지정할 수 있습니다 (런타임 전용은 아님).

근본 원인은 당신이 가질 수 없다는 것입니다 const모든의를 struct달리enum 예를 들어. 시도하면 컴파일되지 않습니다.

한 번 더 이유 struct는 기본 유형이 아닙니다.
.NET의 모든 원시 유형의 목록을 참조 http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
(참고 enum일반적으로 상속 int원시적이다)

그러나 new Guid()상수도 아닙니다!

상수가 필요하다는 말은 아닙니다. 컴파일 타임에 결정할 수있는 것이 필요합니다. Empty필드이므로 필드 값은 컴파일 타임에 알려지지 않았습니다 (런타임의 맨 처음에만).

기본 매개 변수 값이 될 수있는, 컴파일시에 알려 져야 const값, 또는 뭔가처럼 컴파일 타임에 알려진 값을 만드는 C 번호 기능을 사용하여 정의 default(Guid)new Guid()에 대해 컴파일시에 결정된다 ( struct당신은 수정할 수 없습니다로의struct 에서 생성자 암호).

기본 유형이 아니거나 위에서 설명한 것과 같지 않기 때문에 제공 default하거나 new쉽게 제공 할 수는 없습니다 . 다시 말하지만, 선택적 매개 변수 자체에는 상수가 필요하지만 컴파일러에서 알려진 값이 필요합니다.constenum


5
음, 정규 상수 표현식이 필요하지 않습니다 new Guid(). 예를 들어 상수 표현식이 아닙니다. C # 사양은 상수를 포함 하지만 이에 국한되지 않는 허용되는 내용을 매우 명확하게 정의합니다 . (그냥 명확하게하기 위해서는 효율적 이다 C # 사양 측면에서 그냥은 "상수 표현식", 컴파일 시간 상수).
Jon Skeet

3
답장에서 설명 부분을 ​​읽으십시오 . 이 부분에 대한 답변을 추가했습니다.
Meligy

좋은 설명입니다. 감사합니다!
Daryl

default요즘 만 사용할 수 있습니다 :)
Joshit

151

Guid.Empty는에 해당하며 new Guid(), 이는에 해당합니다 default(Guid). 따라서 다음을 사용할 수 있습니다.

public void Problem(Guid optional = default(Guid))

또는

public void Problem(Guid optional = new Guid())

다음과 같은 new Foo()경우 에만 값을 적용 할 수 있습니다.

  • 실제로 매개 변수가없는 생성자를 호출하고 있습니다.
  • Foo 가치 유형

즉, 컴파일러가 알면 실제로 유형의 기본값 일뿐입니다. :)

(재미있게 말하면 99.9 % 가 생성 한 사용자 정의 생성자를 호출하지 않을 것이라고 확신합니다 new Foo(). C #에서는 값 유형으로 이러한 생성자를 만들 수 없지만 IL에서는 그렇게 할 수 있습니다 .)

모든 유형 의 default(Foo)옵션을 사용할 수 있습니다 .


이제 컴파일러 오류 메시지가 왜 이것을 알려주지 않는지, 컴파일러는 Guid.Empty의 경우를 확인하고 더 유용한 메시지를 줄 수 있습니다.
Ian Ringrose

4
@ Ian Ringrose : 컴파일러가 일반적으로 유형별 메시지를 가져야한다고 생각하지 않습니다.
Jon Skeet

2
매개 변수를 기본값으로 새로운 객체로 설정하면 PHP에서 메소드가 호출 될 때마다 새로운 객체가 생성됩니다. 파이썬 에서 전체 프로그램 에 대해 하나의 객체 만 생성합니다 . 실제로, 나는 이것이 파이썬의 디자인 결함 중 하나라고 생각합니다 . C # (및 VB.Net)은 단순히 기본 매개 변수에서 새 객체를 허용하지 않음 으로써이 문제를 피한 것이 다소 기쁩니다 ... PHP 에서이 기능이 실제로 좋은 시간이 있습니다.
BlueRaja-대니 Pflughoeft

1
ASP.NET MVC 컨트롤러 작업에서 이와 동일한 기능이 작동하지 않는 이유는 무엇입니까? 다른 모든 선택적 매개 변수 (int, string)는 작동하지만 GUID에서는 작동하지 않습니다. '/'응용 프로그램의 서버 오류입니다. '.. "코드는 스펙 (default (Guid) 및 new Guid ()) 모두에서 잘 컴파일되지만이 오류가 발생합니다.
mare

@mare : 모르겠어요, 두렵습니다. 또 다른 옵션은을 사용하는 것 Nullable<Guid>입니다.
Jon Skeet

18

사용할 수 없습니다 :

default ( Guid ) ?


1
Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
재귀

4
미안, 나는 의미하지 않았다 ?? 운영자로서 강조된 물음표로-편집하겠습니다!
Nick

9

수락 된 답변이 ASP.NET MVC에서 작동하지 않으며이 런타임 오류가 발생합니다.

[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....

대신 다음을 수행 할 수 있습니다.

public void Problem(Guid? optional)
{
    if (optional == null)
    {
        optional = new Guid();
    }
}

나는 아래로 투표에 대한 이유를 참조하십시오 API이 널 <GUID>를 사용하도록 변경 될 수 있다는 질문 지정 - 공정의 충분한
Majix

빈 Guid 값으로 매개 변수 "선택 사항"을 명시 적으로 지정하지 않는 한 이것이 Guid 유형의 선택적 매개 변수를 정의하는 가장 자연스러운 방법이라고 생각합니다.
Gonzalo Méndez

4

컴파일러는 매우 정확합니다. Guid.Empty컴파일 타임 상수가 아닙니다. 다음과 같이 메소드 과부하를 시도 할 수 있습니다.

public void Problem()
{
    Problem(Guid.Empty);
}

API를 변경하고 싶지 않다고 말했지만 길들이려 고하는 방법은 10 개가 넘습니다!
Ian Ringrose

@Ian Ringrose Guid x = default(Guid)는 솔루션으로 동의하지만 다른 함수 오버로드를 추가해도 선택적 인수를 추가하는 것 이상으로 API가 복잡하지 않다는 것을 기억하십시오. 그것은 실제로 선택적 인수가하는 일입니다.
tenfour February

@tenfour, 10 개의 선택적 parms와 동일하게하려면 많은 새로운 기능 과부하가 필요합니다!
Ian Ringrose

10 개가 넘는 매개 변수가 필요한 공용 함수가있는 경우 단일 인수를 선택적으로 만드는 것이 실제로 해결되지 않을 수도 있습니다. 또한 원래 질문을 되돌아 보면 실제로 " API "(및 10 개의 점과 같이 명시적인 오버로드와 선택적 인수의 차이는 실제로는 미미합니다) 그러나 매개 변수 목록에 대해서는 그런 종류의 괴물이라는 질문에는 언급되지 않았습니다.
CVn

실제로 이것은 문제에 대한 완벽한 해답입니다.
PKD
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.