lock and object passing by ref

G

Guest

Hi,

I get the following warning:
"Possibly incorrect assignment to local 'oLockObject' which is the argument
to a using or lock statement. The Dispose call or unlocking will happen on
the original value of the local."

My code is:
using System;
using System.Collections.Generic;
using System.Text;

namespace RefLockExample
{
class Program
{

protected void MyMethod(ref Object oObject)
{
//something here
//oObject will be used, but no "new" object will be assigned to
oObject
}

static void Main(string[] args)
{
Program oProgram= new Program();
Object oLockObject;
oLockObject = new Object();
lock (oLockObject)
{
oProgram.MyMethod(ref oLockObject);

}

}
}
}

Why does this warning occur?
If I understand it right, it should not make much of a difference to leave
out the "ref".
What does actually get passed here?
I understood that object passing in .NET is passing the reference anyways
and not the value.
So, do I pass the reference on an object reference or do I pass a reference
on the object?

in the called method of course I will not assign anything "new" to the
object, but a problem with assigning anything new would be the same if I
would not have used "ref" also.
What can happen if I use this construct (example) instead of leaving out the
"ref"?

Regards,
 
J

Jon Skeet [C# MVP]

MSDNAndi said:
I get the following warning:
"Possibly incorrect assignment to local 'oLockObject' which is the argument
to a using or lock statement. The Dispose call or unlocking will happen on
the original value of the local."

Yup.

Why does this warning occur?

Because the value of oLockObject may change within the lock.
If I understand it right, it should not make much of a difference to leave
out the "ref".

You don't understand it right, I'm afraid.
What does actually get passed here?

The variable is being passed by reference.
I understood that object passing in .NET is passing the reference anyways
and not the value.

The value of that variable *is* a reference. By default, parameter
passing is always done by value - but that value is often a reference.
This is *not* the same as passing the parameter *by* reference.
So, do I pass the reference on an object reference or do I pass a reference
on the object?

You're passing the variable oLockObject by reference.

I suggest you read http://www.pobox.com/~skeet/csharp/parameters.html

Jon
 
G

Guest

Jon,

thanks for your reply.

I think we mean similar things, but I just expressed myself badly.
I understand what value types, immutable types and "true" (mutable)
reference types are.
The problem of my posting was maybe that I did not point out clearly that I
wanted to talk about mutable reference types only where I will not change the
actual object assignment but only modify the object itself.
So with
"I understood that object passing in .NET is passing the reference anyways
and not the value.
....
So, do I pass the reference on an object reference or do I pass a reference
on the object?"
you replied
"
The value of that variable *is* a reference. By default, parameter
passing is always done by value - but that value is often a reference.
This is *not* the same as passing the parameter *by* reference.
....
You're passing the variable oLockObject by reference.
"
Thus in my (inaccurate) way of asking/expressing it you are saying (in this
specific case of a mutable reference type) that I pass an object reference
by reference.
(I know, "by reference" is different from passing the "reference" since the
object I am working on in the called component is not the passed reference,
but the "by reference" object).

Where I am unsure is what the compiler would do if I pass a mutable
reference type by reference... that maybe the compiler would make no
difference between
ref SomeMutableReferenceType
and
SomeMutableReferenceType.
It would not surprise me if the compiler would "optimize" ref
SomeMutableReferenceType to SomeMutableReferenceType.

In your excellent article you e.g. write about passing a value type by
reference and tell the difference between passing a struct IntHolder and a
class IntHolder, but I do not see an example for the difference of passing a
(mutable) reference type by reference.


Thanks anyways,
 
J

Jon Skeet [C# MVP]

MSDNAndi wrote:

Where I am unsure is what the compiler would do if I pass a mutable
reference type by reference... that maybe the compiler would make no
difference between
ref SomeMutableReferenceType
and
SomeMutableReferenceType.
It would not surprise me if the compiler would "optimize" ref
SomeMutableReferenceType to SomeMutableReferenceType.

It can't do that - the semantics are completely different.
In your excellent article you e.g. write about passing a value type by
reference and tell the difference between passing a struct IntHolder and a
class IntHolder, but I do not see an example for the difference of passing a
(mutable) reference type by reference.

I give an example where a StringBuilder parameter is passed by
reference. The point is that when a parameter is passed by reference,
the value of the variable in the actual parameter can change, which it
can't when the parameter is passed by value. So:

public void MakeMeNull (StringBuilder sb)
{
sb = null;
}

....

StringBuilder x = new StringBuilder();
MakeMeNull(x);

does nothing, but:

public void MakeMeNull2 (ref StringBuilder sb)
{
sb = null;
}

StringBuilder x = new StringBuilder();
MakeMeNull2(ref x);

leaves x with a value of null.

Jon
 
G

Guest

MSDNAndi said:
Hi,

I get the following warning:
"Possibly incorrect assignment to local 'oLockObject' which is the argument
to a using or lock statement. The Dispose call or unlocking will happen on
the original value of the local."

My code is:
using System;
using System.Collections.Generic;
using System.Text;

namespace RefLockExample
{
class Program
{

protected void MyMethod(ref Object oObject)
{
//something here
//oObject will be used, but no "new" object will be assigned to
oObject
}

Simple example:

protected void MyMethod(ref Object oObject)
{
oObject = new Object();
}

this means that you're passing back a new object, so the following code:

lock (oLockObject)
{
MyMethod(ref oLockObject);
}

could mean that it locks one object, changes it through the method call,
and thus tries to unlock the new object. This is what the warning is
about, that this isn't going to happen, that it's the original object
(which is now replaced with a new one) that is going to be unlocked.

Of course, as you say, you don't replace the object, but the compiler
doesn't know that.
 
G

Guest

Hi Jon,

yes, but I was not talking about assigning a newly created object or a
"null" value to the object, but only about the case where I modify the
content of the object.

class IntHolder
{
public int intValue;
IntHolder()
{}
}
Difference between
protected void ModifyIntholderByRef(ref IntHolder myIntHolder)
{
myIntHolder.intValue=1;
}

protected void ModifyIntholder(IntHolder myIntHolder)
{
myIntHolder.intValue=2;
}

I am not assigning anything to myIntHolder itself in the called methods.

IntHolder localIntHolder =new IntHolder()
localIntHolder.intValue=0;



with the calls:
ModifyIntHolderByRef(ref localIntHolder);

or:
ModifyIntHolder(localIntHolder);


What would be the difference in this example (again: no assignments to
myIntHolder in the methods, and no "structs")?

Thanks for you patience,
 
J

Jon Skeet [C# MVP]

MSDNAndi said:
yes, but I was not talking about assigning a newly created object or a
"null" value to the object, but only about the case where I modify the
content of the object.

In that case, you shouldn't pass the parameter by reference - and the
compiler doesn't know that that will be the case.
with the calls:
ModifyIntHolderByRef(ref localIntHolder);

or:
ModifyIntHolder(localIntHolder);

The compiler doesn't know that ModifyIntHolderByRef doesn't really
change the value of the parameter - it's been told to pass something by
reference, so it's going to pass it by reference. Don't forget - other
things could get involved, such as the debugger - to maintain the
correct semantics, if localIntHolder is changed in the debugger at
runtime, that change must get propagated to the call site.
What would be the difference in this example (again: no assignments to
myIntHolder in the methods, and no "structs")?

The difference is in the method signature, which tells the runtime what
to do with the parameters.

If you have no intention of changing the value of a parameter, you
shouldn't declare the parameter as "ref".

Jon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top