13

I wish to say:

public void Problem(DateTime optional = DateTime.MaxValue)
{
}

But the compiler complains that DateTime.MaxValue is not a compile time constant.

DateTime.MinValue is easy, just use default(DateTime)

see also "How do I default a parameter to Guid.Empty in C#?"

I do not wish to use method overloading, as the method I am trying to tame has 101 parameters!

Community
  • 1
  • 1
Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
  • 2
    @Sam Holder But how did an OP with 8.5k end up with 101 parameters to his method? I've never had that occur to me. I'd really like to know why this appears to be the best design. There seems to be an insane level of coupling there. Intuitively I would be surprised if you get good `code metrics` for a method like that. – Simen S Apr 04 '11 at 13:23
  • @Sam Holder to quote Jerry Seinfeld: "If you've got a t-shirt with blood stains all over it maybe laundry isn't your biggest problem right now". The DateTime issue seems peripheral to the parameter issue. – Simen S Apr 04 '11 at 13:28
  • 3
    @Simen well, 101 parameters can occur in a number of ways. Legacy systems; teams of developers expanding behaviour because of lack of time to refactor (thus incurring technical debt); and of course, as is this case, massive sarcasm. Plus what makes you think that the 101 parameters are his doing? – Adam Houldsworth Apr 04 '11 at 13:35
  • @Adam It was not my intent ot to blame anyone. I was rather trying to point out that - personally - I would have attempted to refactor the code in the scenario described by OP rather than trying to make the datetime fit. Maybe I should start a separate question thread to seek the answer to my "Can 101 parameters in a method signature ever be the *correct* programming practice?" – Simen S Apr 04 '11 at 13:48
  • 1
    @Simen: Don't bother... It's never *correct* programming practice. No one has made that point. They're just saying it's not *impossible* to end up with code that completely abhors good programming practices. You did, in fact, ask the question "how" the OP ended up with such code. – Cody Gray - on strike Apr 04 '11 at 13:50
  • and the 101 params is tongue in cheek I'm sure. They are just representative of 'many', to avoid the 'create overload' answers which have been posted. – Sam Holder Apr 04 '11 at 13:58
  • possible duplicate of [C# 4.0: Can I use a TimeSpan as an optional parameter with a default value?](http://stackoverflow.com/questions/2168798/c-sharp-4-0-can-i-use-a-timespan-as-an-optional-parameter-with-a-default-value) – nawfal May 16 '13 at 10:52

8 Answers8

12

I would substitute this for something like:

public void Problem(DateTime? optional = null)
{
   DateTime dateTime = optional ?? DateTime.MaxValue
   // Now use dateTime
}
NewTom
  • 109
  • 2
  • 9
Ilya Kogan
  • 21,995
  • 15
  • 85
  • 141
  • 1
    This looks liek the least bad option, given I can't rewrite the code base. – Ian Ringrose Apr 06 '11 at 09:40
  • 7
    @IanRingrose You might also want to write it using [the null-coalescing operator](http://msdn.microsoft.com/en-us/library/ms173224.aspx), that is: `DateTime dateTime = optional ?? DateTime.MaxValue;` – Jeppe Stig Nielsen Oct 29 '12 at 21:00
5

According to one of your comments, you are trying to make a method with 101 parameters more usable for the callers.
I strongly suggest, that you create a parameter class and initialize the properties of that class with the default values. Provide an overload for your method that accepts only one parameter: The parameter class.
This will really improve the usage of your method, because the user can even reuse its parameter class instance if he needs to change only one parameter.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • I was thinking more along the lines of _multiple_ parameter classes. It would be odd if some of these parameters didn't "belong together in groups". – Simen S Apr 04 '11 at 13:53
  • @Simen: Without knowing his code, we can't know, but your suggestion makes sense, if they belong in groups. – Daniel Hilgarth Apr 04 '11 at 13:57
  • I guess there could be scenarios where a single class is dealing with a lot of atomic information elements that are very unrelated: e.g. if you are attempting to define a strongly typed interface between a weakly typed config file and the core of your application. Still, I believe it should be avoided to pass them all through a single method call. – Simen S Apr 04 '11 at 14:01
4

You can define multiple functions:

public void Problem()
{
     Problem(DateTime.MaxValue);
}
public void Problem(DateTime optional)
{
     // do your stuff here.
}

If you call Problem() (without parameter) that function calls the other function with a parameter.

SynerCoder
  • 12,493
  • 4
  • 47
  • 78
  • This is potentially confusing. Both methods appear at first glance to have the same signature. The C# spec [tells us](http://stackoverflow.com/questions/2674417/c-4-conflicting-overloaded-methods-with-optional-parameters) that the compiler will prefer the method *without* optional parameters, but you shouldn't rely on everyone expecting that behavior. The other suggested solutions are much clearer and more maintainable. – Cody Gray - on strike Apr 05 '11 at 06:30
3

I'm not familiar with C#4.0, but in c#3.5 I'd use overloading;

public void Problem()
{
    Problem(DateTime.MaxValue);
}
public void Problem(DateTime dt)
{
}

And call it with either:

Problem(); //defaults to maxvalue
Problem(myDateTime); //uses input value

Edit: Just to put an answer to some of the comments;

public class FooBar
{
    public bool Problem()
    {
        //creates a default person object
        return Problem(new Person());
    }

    public void Problem(Person person)
    {
        //Some logic here
        return true;
    }
}

public class Person
{
    public string Name { get; private set; }
    public DateTime DOB { get; private set; }
    public Person(string name, DateTime dob)
    {
        this.Name = name;
        this.DOB = dob;
    }

    /// <summary>
    /// Default constructor
    /// </summary>
    public Person()
    {
        Name = "Michael";
        DOB = DateTime.Parse("1980-07-21");
    }
}
firefox1986
  • 1,602
  • 11
  • 9
  • 3
    @Ian: hahaha, omg!! I think you have a completely different problem there! Use a parameter class. 101 parameters...! – Daniel Hilgarth Apr 04 '11 at 13:09
  • @Ian Ringrose You should never have more than 5(?) parameters in any given method or constructor. As @Daniel suggested, abstract these parameters into a ProblemsArgs class and pass this in instead. – firefox1986 Apr 04 '11 at 13:23
  • @Ian-Ringrose see edit with example on passing in an args class. – firefox1986 Apr 04 '11 at 13:28
3

What you're asking to do is simply not possible. DateTime.MaxValue is not a compile-time constant; it's actually a read-only field that is initialized at runtime by a static constructor. That difference becomes quite critical here. Optional parameters require compile-time constants, as they bake the value directly into the code.

However, the real problem is that your method takes 101 parameters. I've never seen anything crying out so loudly for refactoring. My recommendation would be change your method to accept an instance of a class, instead. That will also give you more flexibility in specifying default values for individual properties of the class. In particular, you'll be able to specify values that are not compile-time constants.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
2

The simple answer is you can't with optional parameters I don't think.

you could use an overload if this is the only parameter. If this is an example for a method with many optional params, then this might not be feasible.

What you could do is make it DateTime? and pass null, then interpret null as DateTime.MaxValue in your method.

There is a good write up of optional arguments which I'll dig up for you.

EDIT

article here

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
  • -1: Your suggestion is pretty bad, because null is generally seen as an equivalent of `default(T)`. You would be changing semantics with your approach pretty heavily. The correct way would be to use an overload. – Daniel Hilgarth Apr 04 '11 at 13:08
  • 1
    @Daniel hardly, along with `default(DateTime)` with a subsequent internal check, this is an entirely valid alternative... even usage wouldn't change because giving it a null `DateTime?` would still trigger the default value. – Adam Houldsworth Apr 04 '11 at 13:10
  • an overload may not be feasible if the method has many parameters and the OP is just giving an example for the question. If this is the only param then yes an overload is better. I was only suggesting an alternative if he wants to use an optional param, as I don't think he can get his desired behaviour any other way and still have it as an optional parameter. – Sam Holder Apr 04 '11 at 13:11
  • @Adam: What I was talking about is [POLS](http://en.wikipedia.org/wiki/Principle_of_least_astonishment). When calling a method with a null value for one parameter, I wouldn't expect, that this is interpreted as `MaxValue`. – Daniel Hilgarth Apr 04 '11 at 13:16
  • 1
    @Daniel, even if the parameter was called `endDate`? I think its all about context. Depending on the situation you may want null to mean different things, for eaxmple a method with 2 args StartDate and EndDate which can both be null and might both default to different values, startDate to DateTime.MinValue and EndDate to DateTime.MaxValue and this might be sensible in the specific situation, indeed I have seen a class for a timespan which does exactly this. I was only giving the OP an option, other than the obvious 'create an overload' which I assumed he would've done if it was that simple – Sam Holder Apr 04 '11 at 13:23
  • @Sam: I agree with your context argumentation and hence removed my down vote. – Daniel Hilgarth Apr 04 '11 at 13:24
  • @Sam: You are welcome. BTW: The current down vote isn't from me, just so you know... – Daniel Hilgarth Apr 04 '11 at 14:03
2

If, as you stated in one of your comments, your method has a lot of parameters, you can possibly turn them all into a parameter class and use its property initializers. Then you won't have to initialize all properties, and you can set the date to DateTime.MaxValue in the constructor of that class.

Ilya Kogan
  • 21,995
  • 15
  • 85
  • 141
1

loadDefault parameter values are constants, that is, it can't be string.Empty/Guid.Empty and etc. You can use a method overload:

void M(int intValue)
{
   M(intValue, Guid.Empty);
}
void M(int intValue, Guid guid)
{
   //do something
}
Sam Holder
  • 32,535
  • 13
  • 101
  • 181
Cheng Chen
  • 42,509
  • 16
  • 113
  • 174