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.