24

Consider a method like this:

public void WorkAt(string location = @"home")
{
    //...
}

It can be called by passing a value explicitly, like:

WorkAt(@"company");
WorkAt(@"home");

Or just use the default value, like:

WorkAt();

Is there a way to know whether the default value is used?

For example, I want to code like this:

public void WorkAt(string location = @"home")
{
     if ( /* the default value is used unexplicitly */)
     {
         // Do something
     }
     else
     {
         // Do another thing
     }
}

Be careful that WorkAt("home") is different from WorkAt() in this context.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Woo
  • 446
  • 3
  • 13
  • 1
    Whats about `if (location == "home") { }` – NASSER Aug 24 '15 at 05:17
  • 1
    you already defined it. why not check `if (location == @"home")` ??? – Anonymous Duck Aug 24 '15 at 05:17
  • 1
    Why don't you use additional parameter, boolUseDefault? – Amnesh Goel Aug 24 '15 at 05:18
  • If you have `WorkAt()` with no parameters, then how would you even be able to call `WorkAt(string location = "home")` without passing in a parameter? – Andrew Shepherd Aug 24 '15 at 05:21
  • 12
    By the way, why are you using `@`? – NASSER Aug 24 '15 at 05:22
  • @X-TECH It's verbatim string, see http://stackoverflow.com/questions/556133/whats-the-in-front-of-a-string-in-c. I just use it often even when doesn't need. :-) – John Woo Aug 24 '15 at 05:38
  • 5
    @JohnWoo I already know about it, but here it is useless. – NASSER Aug 24 '15 at 05:39
  • 6
    Well you stop using it where you don't need it. – Bauss Aug 24 '15 at 06:01
  • 4
    The question should be improved to clarify **why** you need/want to do this. There might then be appropriate answers to that problem. If it's simple curiosity, it's not the same as an actual business problem that needs to be overcome. – user2338816 Aug 25 '15 at 01:04
  • 3
    @user2338816 half the problem with questions on this site are users asking how to dig a hole with their hatchet, rather than asking for the correct tool to use to dig a hole. – James T Aug 25 '15 at 10:02
  • 1
    @JamesTrotter And that's provided they really should to be digging a hole in the first place. For example it would be a much better solution to fly halfway around the world than to try to dig through the earth's core to the other side, no matter how convinced you are that you really want to dig that hole. – lc. Aug 25 '15 at 16:17

7 Answers7

66

There is not, and should not be, any reason to do this. The default value is there to do just that - provide a default value when none is specified.

If you need to perform a different function based on what is passed, I suggest overloading the method. For example:

public void WorkAt()
{
    //do something
}

public void WorkAt(string location)
{
    //do other thing
}

Alternatively, if there is shared logic, you could use an additional parameter:

public void WorkAt(string location = "home", bool doOtherThingInstead = false)
{
    if (!doOtherThingInstead)
    {
        //do something
    }
    else
    {
        //do other thing
    }

    //do some shared logic for location, regardless of doOtherThingInstead
}

As a side note, perhaps the example in the question was contrived, but WorkAt() with no parameter specified makes no lexical sense. One would expect a value after the word at. Perhaps you may want to rename the second method WorkAtDefaultLocation().

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
lc.
  • 113,939
  • 20
  • 158
  • 187
  • 13
    Now OP will come up asking how to find `doOtherThingInstead = false` passed explicitly ? :P – Sriram Sakthivel Aug 24 '15 at 05:24
  • 22
    @SriramSakthivel In which case I'll have to recursively refer them to this answer. Hmm, I think we've just had a stack overflow on Stack Overflow. :-P – lc. Aug 24 '15 at 05:26
  • 1
    _There is not,_ actually its possible. [take a look at my answer](http://stackoverflow.com/a/32176490/4767498). – M.kazem Akhgary Aug 24 '15 at 11:33
  • 1
    A better solution for the second situation is a third function, probably private, that both overloads call, specifying a Boolean to tell it which overload it came from – Nick Mertin Aug 24 '15 at 12:05
  • 5
    @M.kazem Akhgary It may be possible, and is an interesting exercise, but there is still no reason to do it. The OP says WorkAt("home") is different from WorkAt(). If they are different, then make them different. It makes a lot less sense to try to make them the same. – Mohair Aug 24 '15 at 16:27
  • @Mohair true. using overloads is exactly what OP needs. – M.kazem Akhgary Aug 24 '15 at 18:43
10

Your answer might be something like the following code.

public void CommonOperations(/*Some parameteres as needed.*/)
{
    // Shared operations between two methods.
}
public void WorkAt()
{
    string location = "home";
    CommonOperations(/*Some parameteres as needed.*/);
    //do something
}

public void WorkAt(string location)
{
    CommonOperations(/*Some parameteres as needed.*/);
    //do the other thing
}

I hope it will help.

Mohammad Chamanpara
  • 2,049
  • 1
  • 15
  • 23
9

You can use ReferenceEquals for this purpose.

However the string you are sending should not be a compile time constant, otherwise string "home" has the same reference with default value "home" and will return true. Why?

In order to create a string with a different reference you have to make a deep copy from that string.

    static void Main()
    {
        WorkAt(); // Prints true
        WorkAt("home"); // Prints true because the string is a compile-time constant

        // DeepClone before passing parameter to WorkAt.
        WorkAt(DeepClone("home"));// Prints false for any string.
    }

    static void WorkAt(string location = @"home")
    {
        if (ReferenceEquals(location, @"home")) // Only true when using default parameter
        {
            Console.WriteLine(true);
        }
        else
        {
            Console.WriteLine(false);
        }
    }

    static string DeepClone(string str) // Create a deep copy
    {
         return new string(str.ToCharArray());
    }

Note that this is the only way to understand if the default value is used or not. because the default value is always compile-time constant but the parameter sent to the method is not.

BTW as @lc. explained there is actually no reason to do this since you can use method overloads.

Community
  • 1
  • 1
M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118
7

Use a sentinel value instead of the default

public void WorkAt(location="default_sentinel_value") {
    if (location == "default_sentinel_value") {
        location = "home";
        ...
    }
    else
    {
        ...
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • But then what if someone passes the sentinel (`WorkAt("default_sentinel_value")`). He said, how can he detect the difference between `WorkAt()` and `WorkAt("home")`? You can't without function overloads. – Cole Tobin Aug 24 '15 at 10:29
  • he can detect the difference between WorkAt() and WorkAt("home") but not between WorkAt() and WorkAt("sentinel"). Of course the sentinel value should not be one of the meaningful values –  Aug 24 '15 at 10:57
  • 3
    If `null` is not a valid value for the function you could use null as a sentinel value. – Falco Aug 24 '15 at 12:31
  • This is the approach I would take - with "sentinel value" being something that is extremely unlikely (maybe even invalid) as an input. It could be a string of 192 random characters... – Floris Aug 24 '15 at 14:38
  • 1
    Why not just create a private static field initialized to any object (i.e. not null) and then check reference equality? – Kevin Aug 24 '15 at 16:10
  • 3
    @Kevin: as long as the runtime doesn't intern the strings while you're not looking. If it does then your sentinel might not be as private as you think, but M.kazem's answer proposes a means to prevent interning. – Steve Jessop Aug 24 '15 at 18:56
  • @SteveJessop: That's why I like dynamic languages: you can just use `Object()` as a sentinel value, never mind the gross lack of type safety. – Kevin Aug 24 '15 at 20:59
2

As a programmer, the default value is a known value, so you can code like any of the following methods:

Method 1:

public void WorkAt(string location = @"home")
{
    if (location == @"home")
    {
        // Do something
    }
    else
    {
        // Do another thing
    }
}

Method 2: Make use of function Over loading

//function(A) with default value
public static void samplemethod()
    {
       string defaultValue="home";
       //Do something
    }

//function (B) without default value
public static void samplemethod(string x)
    {
         //Do something
    }

Then samplemethod("someValue"); will call function(B) and samplemethod(); will call function(A)

sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
2

If you use OO, you can just create some GetSet property.

private string pvt_default;
private string pvt_location;
public string location
{
    get
    {
        return this.pvt_location;
    }
    set
    {
        if (pvt_default == location)
        {
            // do somthing
        }
        this.pvt_location = location;
    }
}
KodornaRocks
  • 425
  • 3
  • 14
  • What does this even have to do with the question!? – Cole Tobin Aug 24 '15 at 10:30
  • IMHO WorkAt could be used as a property of his class instead of methods. Then, he could also have the get/set beneficts. – KodornaRocks Aug 24 '15 at 10:39
  • 1
    Personally, I disagree (but not going to downvote) as changing where you're working may require effort (transportation, etc). It just doesn't seem right to use getters/setters on _actions_. – Cole Tobin Aug 24 '15 at 22:57
  • It's all about where the application will be focused at and what you enjoy typing. I really like doing everything "objected" in c#. When running low demand softwares it helps to serialize/unserialize, use EVA storages and other things. And if it was on getters/setters your setter could also change the transportation part, that for itself could increment a stack of tickets. And LINQ helps a lot when using properties. Today I'm working with bigdata, so, totally another approach. C# just isn't even a option. – KodornaRocks Aug 25 '15 at 06:04
2

Change default value to null and change it to @"home"

Waters
  • 343
  • 1
  • 11