85

This is my method signature. While trying to pass end as an optional parameter it gives me this error. What should I do to resolve this? Why isn't DateTime.MinValue a constant?

public static void DatesToPeriodConverter(DateTime start, DateTime end = DateTime.MinValue,
                                          out string date, out string time)
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
Ankit
  • 6,554
  • 6
  • 49
  • 71
  • @Marc Gravell: my bad.. I thought I looked everywhere.. I'm going to delete my comment... Just to strengthen the idea so that any visitor can notice it easily: So it's not just the issue with the constant value, there are actually 2 totally different reasons why one would want to write overloads.. The second one is the order of *out* and *optional* parameters. Both these types of parameters are required to be last. – Eduard Dumitru Sep 11 '13 at 12:03

8 Answers8

110

DateTime.MinValue is not a const, because the language doesn't like const on DateTime. One option is to use DateTime? instead, i.e.

public static void DatesToPeriodConverter(DateTime start, DateTime? end = null,
     out string date, out string time)
{
    var effectiveEnd = end ?? DateTime.MinValue;
    // ...
}

However, you will still have the issue of having non-default parameters after default parameters - you may need to re-order them to use that as a default.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 4
    I think this is the best solution. I usually prefer to go with null rather than .MinValue/.MaxValue and other "magic" values as defaults. It's clearer, less error-prone and more precise: null means no value was given. No more, no less. – Bas Sep 11 '13 at 11:58
  • 5
    @student I use several here; the `DateTime?` means `Nullable`, meaning "a value that can either be a `DateTime` or `null`"; the `??` is the null-coalescing operator, which means (in this context): take the first non-null value, i.e. take `end` if it is non-null, otherwise `DateTime.MinValue` – Marc Gravell Jun 27 '14 at 13:33
  • I much prefer this approach compared to method overloading – Ben D Apr 01 '19 at 13:13
  • @MarcGravell what is the benefit to put such a parameter, since you want to put a value which is a constant. You might go – Ando Jurai Nov 22 '19 at 20:14
  • 1
    @Ando because it can at least be expressed in the language, with the value in the body code – Marc Gravell Nov 23 '19 at 09:03
  • 1
    `end ??= DateTime.MinValue;` – 5andr0 Sep 16 '21 at 22:01
29

Use regular method overloads instead:

public static void DatesToPeriodConverter(DateTime start, out string date, out string time)
{
    DatesToPeriodConverter(start, DateTime.MinValue, out date, out time);  
}

public static void DatesToPeriodConverter(DateTime start, DateTime end, out string date, out string time) 
{ }

Atlernatively, default(DateTime) is the same as DateTime.MinValue and is compile time constant, but I tend to err away from using this style (there's no guarantee in future that default(DateTime) will equal DateTime.MinValue):

public static void DatesToPeriodConverter(DateTime start, DateTime end = default(DateTime), out string date, out string time)

Or as Marc suggests, use DateTime? which allows a null default value.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • 3
    Aside: it is intriguing that `=default(DateTime)` *works* here, when `const DateTime x = default(DateTime);` does *not*. – Marc Gravell Sep 11 '13 at 11:58
  • @MarcGravell Crazy, you are right, I've never noticed that. Might make a good question. – Adam Houldsworth Sep 11 '13 at 11:59
  • @MarcGravell Found out the answer, seems to be a compiler red-herring, as `const int MyInt = default(int)` works fine, the compiler first complains that `DateTime` is not actually a valid const. – Adam Houldsworth Sep 11 '13 at 12:15
  • 1
    @MarcGravell: It makes perfect sense when you consider that `=null` works for references, even though you can't declare a reference as `const`. Supporting `const` for datatypes which have exactly one valid `const` strikes me as somewhat unnecessary. On the other hand, supporting `=null` for default arguments is obviously useful. – Brian Sep 11 '13 at 13:48
  • 1
    I wanted to do something like `class Foo { public Foo(List items = new List()) { } }`. Changing `new List()` to `default(List)` solved the problem for me – binaryfunt Mar 17 '18 at 00:46
  • @binaryfunt I would probably err away from this. `default(List)` is just a reference type so will return `null`. Instead, I would aim for clarity by either stipulating null as the default (so the contract states null is a valid input) or disallow nulls completely and force the caller to provide an empty list. If an empty / null list is allowed, do you actually need a list within that method or just `IEnumerable`? – Adam Houldsworth Mar 19 '18 at 10:28
  • @AdamHouldsworth I swear I tried doing `List items = null` and IntelliSense didn't like it, but I've just tried again and it seems to be fine. Strange. – binaryfunt Mar 19 '18 at 14:07
8

You can try doing it this way:

public static void DatesToPeriodConverter(DateTime start, DateTime? end , out string date, out string time)
{
    if(!end.HasValue){
        end = DateTime.MinValue;
    }
}
Adam Moszczyński
  • 3,477
  • 1
  • 17
  • 18
  • Work great! Can simplify this using Coalesce, replace the entire if statement with: end = (end ?? DateTime.MinValue) – Geordie Aug 01 '21 at 06:21
  • I like this methods because it stops the propagation of nullable types through your code. – Geordie Aug 01 '21 at 06:23
7

Change a type of the parameter end to a Nullable and use null as a default value:

public static void DatesToPeriodConverter(DateTime start, DateTime? end = null, out string date, out string time)

or use default(DateTime) as a default value:

public static void DatesToPeriodConverter(DateTime start, DateTime end = default(DateTime), out string date, out string time)
Viacheslav Ivanov
  • 1,535
  • 13
  • 22
3

You are correct. Default parameter for value must be a compile time constant. Dynamically calculated value is not accepted by compiler against optional parameter. The reason behind this may be that it is not definite that the dynamic value you are providing would give some valid value.

Adarsh Kumar
  • 1,134
  • 7
  • 21
2

Optional parameters must appear at the end of the parameter list. out parameters must also appear at the end of the parameter list. Your optional parameter is not an out parameter.

Furthermore, you can't use default values for optional parameters other than literal constants and a few weird corner cases.

All facts point in the following direction:

  • Create a secondary overload method.
  • Make the initial method not include the parameter
  • Make the secondary one include the parameter
  • Call your more general method (the one with the parameter) from your more specific one and implement the logic only in the more general one
Eduard Dumitru
  • 3,242
  • 17
  • 31
1

This error can happen with Lists as well:

CS1736 Default parameter value for 'dateTimes' must be a compile-time constant

public YourEntity(dateTimes = new List<DateTime>())
{
    DateTimes = dateTimes;
}

public List<DateTime> DateTimes { get; set; } = new List<DateTime>();

You can solve it like this then:

public YourEntity(dateTimes = null)
{
    DateTimes = dateTimes != null ? dateTimes : new List<DateTime>();
}

public List<DateTime> DateTimes { get; set; } = new List<DateTime>();
Ogglas
  • 62,132
  • 37
  • 328
  • 418
-3

we can create CONSTANTS class with default values

public const int DEFAULTINT = -9999;

and use them as CONSTANTS.DEFAULTINT as business defaults..

hope it helps,

HydTechie
  • 797
  • 10
  • 17
  • There's no way to assign a value to your constant datetime, as there are no compile time literals for `DateTime`. – Servy Dec 03 '13 at 15:54