210

I wish to say:

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

But the compiler complains that Guid.Empty is not a compile time constant.

As I don’t wish to change the API I can’t use:

 Nullable<Guid> 
2
  • possible duplicate of C# 4.0: Can I use a TimeSpan as an optional parameter with a default value? Commented May 16, 2013 at 10:52
  • 1
    What is wrong with switching to Nullable<Guid> optional = null (or more tersely, Guid? optional = null)? Any Guids currently passed to it will coerce without any code changes needed at all. Commented Dec 22, 2017 at 17:41

5 Answers 5

292

Solution

You can use new Guid() instead

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

You can also use default(Guid)

default(Guid) also will work exactly as new Guid().

Because Guid is a value type not reference type, so, default(Guid) is not equal to null for example, instead, it's equal to calling default constructor.

Which means that this:

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

It's exactly the same as the original example.

Explanation

Why didn't Guid.Empty work?

The reason you are getting the error is because Empty is defined as:

public static readonly Guid Empty; 

So, it is a variable, not a constant (defined as static readonly not as const). Compiler can only have compiler-known values as method parameters default values (not runtime-only-known).

The root cause is that you cannot have a const of any struct, unlike enum for example. If you try it, it will not compile.

The reason once more is that struct is not a primitive type.
For a list of all primitive types in .NET see http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
(note that enum usually inherits int, which is a primitive)

But new Guid() is not a constant too!

I'm not saying it needs a constant. It needs something that can be decided in compile time. Empty is a field, so, it's value is not known in compile time (only at very beginning of run time).

Default parameter value must be known at compile-time, which may be a const value, or something defined using a C# feature that makes value known at compile time, like default(Guid) or new Guid() (which is decided at compile time for structs as you cannot modify the struct constructor in code).

While you can provide default or new easily, you cannot provide a const (because it's not a primitive type or an enum as explained above). So, again, not saying that optional parameter itself needs a constant, but compiler known value.

Sign up to request clarification or add additional context in comments.

4 Comments

Well, it doesn't need a normal constant expression - new Guid() isn't a constant expression, for example. The C# spec defines quite clearly what's allowed, including but not limited to constants. (Just to be clear, it effectively is a compile time constant, just not a "constant expression" in C# spec terms).
Read the part Explanation in my reply. Added to answer this part.
You can use only default nowadays :)
152

Guid.Empty is equivalent to new Guid(), which is equivalent to default(Guid). So you can use:

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

or

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

Note that the new Foo() value is only applicable when:

  • You're really calling the parameterless constructor
  • Foo is a value type

In other words, when the compiler knows it's really just the default value for the type :)

(Interestingly, I'm 99.9% sure it won't call any custom new Foo() constructor you may have created. You can't create such a constructor in a value type in C#, but you can do so in IL.)

You can use the default(Foo) option for any type.

5 Comments

Now why does the compiler error message not tell me this, the complier could check for the case of Guid.Empty and give a more helpfull message.
@Ian Ringrose: I don't think the compiler should have type-specific messages in general, to be honest.
Setting a parameter to default to a new object creates a new object every time the method is called in PHP; but only creates one object for the entire program in Python. Really, I consider this to be one of the very few design flaws of Python. I'm somewhat glad C# (and VB.Net) avoided this issue by simply disallowing new objects in default parameters... though there are times where this ability is really nice in PHP.
what could be the reason that this same thing wouldn't work in ASP.NET MVC controller action? All other optional parameters work (int, string) but it doesn't work for GUID, says "Server Error in '/' Application. The parameters dictionary contains a null entry for parameter 'categoryId' of non-nullable type 'System.Guid' .." The code compiles fine with both specifications (default(Guid) and with new Guid()) but issues this error.
@mare: I don't know, I'm afraid. Another option would be to use Nullable<Guid>, potentially.
18

Can't you use:

default ( Guid ) ?

2 Comments

No. Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
Sorry, I didn't mean ?? as an operator but as an emphasised question mark - I'll edit!
13

The accepted answer does not work in ASP.NET MVC, and cause this run-time error:

[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)' .... 

Instead, you may do the following:

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

2 Comments

I see the reason for down-voting: The question specifies that API cannot be changed to use Nullable<Guid> - fair enough
Unless you want to explicitly assign the paramter "optional" with an empty Guid value, I think this is the most natural way for defining an optional parameter of type Guid.
3

The compiler is quite correct; Guid.Empty is not a compile-time constant. You can try making a method overload like this:

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

5 Comments

I said I did not wish to change the API, the method I am trying to tame has overe 10 parms!
@Ian Ringrose, though I agree with Guid x = default(Guid) as the solution, remember that adding another function overload doesn't complicated the API any more than adding an optional argument. That's really what an optional argument does anyway.
@tenfour, it would have to be many new function overloads to do the same as 10 optional parms!
If you have a public function that requires over ten parameters, maybe making a single argument optional isn't really a fix... Also, looking back at the original question, you do indeed say that you don't want to "change the API" (and like tenfour points out, the difference between an explicit overload and an optional argument is minimal in practice) but there is no mention in the question of the parameter list being that kind of a monster.
Actually, this is a perfect answer to the problem.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.