다음을 통해 공유


C#: Passing parameters

This is a subject which can confuse even quite experienced developers.  Probably as a result, this is quite often brought up as a sort of “trick” question by interviewers.

Some people feel this “sorts the men from the boys”. 

Others might suggest that a practical understanding of what happens is more important than the theory.  Having said that, once one is confident on the practical effect it is easier to learn the technical explanation and land that top job.

The Problem

The main reason for confusion is because the words reference and value both have two different meanings.

You have a call by reference which has a different meaning to a reference type.

You have a call by value which has a different meaning to a value type.

Even when you try and substitute different words and say such and such is a pointer to a…..  There are computing meanings for them already.

Perhaps the c# developer should be grateful he/she doesn’t have to worry about Pointer to a Pointer and Reference to a Pointer modifying pointers passed to a function.

The second reason for confusion is that reference types are somewhat confusing by their nature.

OK, that’s the problems.  Let’s start on the explanation.

The Options

There are three alternative ways to pass parameters by.

  • Value
  • Reference
  • Out

By Value

Value is the default and one can see it all the time in eventhandlers:

private void  button1_Click(object  sender, EventArgs e)
{
    Button btn = sender as  Button;
}

Value means that something is passed in but it’s the value of the thing rather than the actual thing itself.

Say the call comes with a variable passed. It’s value is copied into the variable you have inside those parenthesis in the method.

 If the value of that new variable is changed then it’s a different thing totally from the variable on the outside of the method and that value is not passed back.

The complication is what exactly the "value" means for reference types.  The reference type is sort of one value which is directing to the collection of things contained in the type.  It is a reference to some data.  With a Reference type the thing which gets copied is that reference but it’s still pointing to the same bunch of data.

With a reference type if you change a property of it whilst it’s inside the method then that’s changing the same bit of data the pointer in the variable outside the method is pointing to.

All of which means in an eventhandler that sender is a Button reference type and if you change one of it’s properties then that will be returned from the method. If you checked the tag of the Button after this event then the Tag would have changed:

private void  button1_Click(object  sender, EventArgs e)
{
    Button btn = sender as  Button;
    btn.Tag = "This will be returned to the caller";
}

You can change the data the reference is to but you can’t make sender point to a different button because what you would be changing is the reference and that is a copy of the one outside the method.

By Reference

When you prefix a parameter with the keyword ref as you pass it then you are passing by reference. With value types this is a reference to the variable.

With reference types it is a reference to the reference pointing to the data.  

That means you can change the actual object passed back as well as it’s properties.

The following code passes a new object back out as the parameter.

private void  PassAref(ref  object sent)
{
    Button btn = new  Button();
    sent = btn;
}

Out

The out keyword is an expectation that the caller passes  a null variable in but is expecting to get something back.  You need out on both the call and method parameters.  This is probably the least used of the options.

Class OutClass
{
     {
         Button Backout;
         PassOut(out  Backout);
     }
  
     private void  PassOut(out  Button Backout)
     {
         Button btn = new  Button();
         Backout = btn;
     }
}

So there you go, all clear now?
Maybe another way to look at things.

A Metaphor

The difference between call by value and method are quite tricky to follow unless you are steeped in the very essence of C#.  The rest of us less mighty in the programming arts or perhaps not quite so swift on the uptake can take several goes before finally understanding what’s going on.

To fix this in one’s mind it is perhaps an idea to think in metaphorical terms and thus avoid the distracting clash of terminology.

Consider a serving hatch between a dining room and kitchen.

This is the boundary between caller and method.

I am in the kitchen and you are in the dining room.

You walk up to the hatch and ask for a cup of tea.

I pass a cup of tea to you.

This is similar to how out works.You walk up to the hatch with an empty cup and pass it through, asking for a cup of tea.

I fill it with tea and a spoonful of sugar.

I pass the same cup back to you that you passed in, but with your drink in it.

This is the default call (by value ) with a reference type.

Same cup, different content.

You walk up to the hatch with a cup and saucer, pass them through and ask for a cup of coffee.

I take your cup off the saucer, put a clean one on it and fill it with coffee.

Or maybe I’m short of cups so I use the same one you passed in.

The coffee will drown out the taste of the tea, you’ll never notice ;^)

I pass it back to you on the saucer.

The reference is equivalent to the saucer and I can change the object it refers to or keep the same object and change it’s content.

Return to Top

See Also

For further less metaphorical reading: