views:

396

answers:

2

Both of these generate an error saying they must be a compile-time constant:

void Foo(TimeSpan span = TimeSpan.FromSeconds(2.0))
void Foo(TimeSpan span = new TimeSpan(2000))

First of all, can someone explain why these values can't be determined at compile time? And is there a way to specify a default value for an optional TimeSpan object?

+3  A: 

The set of values which can be used as a default value are the same as can be used for an attribute argument. The reason being that default values are encoded into metadat inside of the DefaultParameterValueAttribute.

As to why it can't be determined at compile time. The set of values and expressions over such values allowed at compile time is listed in section 7.18 of the C# lang spec. In terms of values allowed it is limited to

  • Literals including null
  • References to other const values
  • Enumeration values
  • Default value expression

The type TimeSpan does not fit into any of these lists and hence cannot be used as a constant.

JaredPar
+8  A: 

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.

Josh Einstein
That's quite clever.
Mike Pateras
Thats a very nice little solution.
Ian