C# 4.0: How to Use a Timespan as an Optional Parameter with a Default Value

C# 4.0: Can I use a TimeSpan as an optional parameter with a default value?

You can work around this very easily by changing your signature.

void Foo(TimeSpan? span = null) {

if (span == null) { span = TimeSpan.FromSeconds(2); }

...

}

I should elaborate - the reason those expressions in your example are not compile-time constants is because at compile time, the compiler can't simply execute TimeSpan.FromSeconds(2.0) and stick the bytes of the result into your compiled code.

As an example, consider if you tried to use DateTime.Now instead. The value of DateTime.Now changes every time it's executed. Or suppose that TimeSpan.FromSeconds took into account gravity. It's an absurd example but the rules of compile-time constants don't make special cases just because we happen to know that TimeSpan.FromSeconds is deterministic.

Can I use a TimeSpan as an optional parameter with a default value?

This has never worked in any C# version. Defaults must be constants. You have to create an overload to default the value, or make it nullable and default it if the value is null.

Option 1:

public static Foo(string myString)
{
Foo(myString, TimeSpan.FromSeconds(1));
}

public static Foo(string myString, TimeSpan maxWait)
{
// do something
}

Option 2:

public static Foo(string myString, TimeSpan? maxWait = null)
{
TimeSpan maxWaitNotNull = maxWait ?? TimeSpan.FromSeconds(1);
// do something
}

Set default value for DateTime in optional parameter

There is a workaround for this, taking advantage of nullable types and the fact that null is a compile-time constant. (It's a bit of a hack though, and I'd suggest avoiding it unless you really can't.)

public void SomeClassInit(Guid docId, DateTime? addedOn = null)
{
if (!addedOn.HasValue)
addedOn = DateTime.Now;

//Init codes here
}

In general, I'd prefer the standard overloading approach suggested in the other answers:

public SomeClassInit(Guid docId)
{
SomeClassInit(docId, DateTime.Now);
}

public SomeClassInit(Guid docId, DateTime addedOn)
{
//Init codes here
}

C# 4.0: Can I use a Color as an optional parameter with a default value?

I've run into this as well and the only workaround I've found is to use nullables.

public void log(String msg, Color? c = null)
{
loggerText.ForeColor = c ?? Color.Black;
loggerText.AppendText("\n" + msg);
}

Other possible syntax is:

loggerText.ForeColor = c.GetValueOrDefault(Color.Black);

How can I force the use of a default parameter value in C# (skip optional arguments)?

Foo("Hello World", b: 6, d: 1.9f);

Why the default value of an optional parameter must be specified by a constant expression, or a parameterless constructor of a value type?

The creators of C# decided that optional method arguments should not complicate the binary interface of classes, meaning that they should be a source-code-only, syntactic-sugar feature, making use of whatever other mechanisms pre-existed in the language, without adding anything new.

What this means is that for one thing, the default value expression for a given method argument must be fully resolvable at the time that each call to the method is being compiled.

But this requirement should still not prevent you from being able to instantiate a class to pass as a default value to an argument, if the class is known. So, the reality is a bit more complex than that.

In languages like C#, it is always possible to program against an assembly when you only have the DLL in your hands, without the source code. So, a "source-code-only" feature is never exactly source-code-only. In order to add optional method arguments to the language, they had to introduce a little trick: in the definition of a method, for each optional argument the compiler emits a certain attribute, the content of which specifies what the default value of the argument should be. This attribute is not used at runtime, it is used only at compilation time. So, when you are writing a call to that method, and you omit an optional argument, the compiler looks up the optional argument attribute in the target assembly, and knows what value it should pass.

However, attributes in C# also have this restriction: all of their parameters must be compile-time constants. (See ECMA-335 Partition II §21 "Custom attributes" and Partition II §23.3 "Custom attributes".)

So, ultimately, the answer to the question of why default argument values must be compile-time constants is because their implementation involves the use of attributes behind the scenes, and attribute arguments must in turn be compile-time constants.

The technical explanation of why attribute arguments must be compile-time constants is basically because the creators of the language did not want to make things too complicated. Attribute arguments must be so simple that they can be turned into an array of bytes and placed in the binary, and also when loading the class, this array of bytes must be very easily convertible to a set of arguments to pass to the attribute. For what it's worth, the exact same holds true for Java, where "attributes" are called "annotations".

How can I default a parameter to Guid.Empty in C#?

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.

Default values in parameter

Default parameter for value must be a compile time constant. Dynamically calculated value is not accepted by compiler against optional parameter.

Let's say as anlternative DateTime? = null; and in method,

var effective_p_Date_Start = p_Date_Start ?? new DateTime(2006, 1, 1)

If necessary, you can follow up the way for others.



Related Topics



Leave a reply



Submit