I learnt the reference type parameter passing is just a copy of the reference. If you set the passed in refernece parameter point to another object inside the called method, the orginal reference will not change.
I have a test method to test the reference type parameter passing. A refTest(SystemSwEvent systemSwEvent) method is called from that test method with a valid SystemSwEvent type object. Inside the refTest() method, the processEvScanDataAvailable(EvScanDataAvaialble systemSwEvent) method is called. Inside the processEvScanDataAvailable(EvScanDataAvaialble systemSwEvent) method, I set the passed in reference parameter to null. I expect the parameter in refTest() should not be changed. But that is not true. It will be changed to null momentarily. why?
The debugger recognizes the name in the current context and shows the value. It's just a coincidence that you pointed your cursor at a place that actually triggered the currently executing method (the current context).
Also note you can use the Call Stack tool to inspect the parameters of caller methods.
why?
I suspect this is a debugger issue, and not representative of what's actually occurring inside the CLR.
Try using different variable names for your arguments, and this behavior will go away.
Object references are by default (if you don't qualify them with ref or out) passed by value, so the method is receiving a copy of the object reference - setting that copy to null doesn't change the original object reference, so what you claim to see is impossible and most likely you are just misinterpreting what you see in the debugger.
The debugger is getting confused because your parameter and variable have the same name. If you change the name of your parameter, you will notice that that debugger no longer gives information about the variable being passed into the method, but only gives information on the variable inside the method.
Simply change the name of that parameter, and you will no longer have this issue.
Related
I'm a bit confused about the in parameter modifier:
I know if I write in before a parameter it a read only reference, which is faster then passing big stuff by value. According to the documentation https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier it says that the in parameter modifier is optional on the callsite:
Specifying in for arguments at the call site is typically optional. There is no semantic difference between passing arguments by value and passing them by reference using the in modifier. The in modifier at the call site is optional because you don't need to indicate that the argument's value might be changed. You explicitly add the in modifier at the call site to ensure the argument is passed by reference, not by value. Explicitly using in has the following two effects:
First, specifying in at the call site forces the compiler to select a method defined with a matching in parameter. Otherwise, when two methods differ only in the presence of in, the by value overload is a better match.
Second, specifying in declares your intent to pass an argument by reference
When I use it in my code:
public static kAssetKind? DetermineAssetKind(in string extension)...
And I call it here:
...{FilePath = mainFile, Kind = DetermineAssetKind(Path.GetExtension(mainFile)) ?? kAssetKind.Other};
it's okay the string is passed by reference, but if I write specifically in before:
DetermineAssetKind(in Path.GetExtension(mainFile))
then I get an error that it could be passed by reference. So there is a difference between an in on callsite and it says "Second, specifying in declares your intent to pass an argument by reference" but I thought it will pass it by reference even if I don't use in at the callsite? And does it even make sense to pass a string as in reference because classes are reference?
I think you are misunderstanding the article.
The way I understand it is that considering the following method:
void Foo(in SomeBigValueType t)
{ ... }
The following two calls are the same:
SomeBigValueType v;
Foo(v);
Foo(in v);
Your issue seems to be unrelated to the article. in needs a storage location (aka variable). In your second example you aren’t passing one so you get an error; you’d get the same error with ref or out.
From my understanding passing a variable by reference means that the original variable that was passed into a function's parameters is changed. But also from my understanding a static variable means that the variable is changed when used as a parameter of a function. So don't both of these do the same thing?
From my understanding passing a variable by reference means that the original variable that was passed into a function's parameters is changed.
That location is passed, so yes; since the caller supplied the location, the caller can see the change.
But also from my understanding a static variable means that the variable is changed when used as a parameter of a function.
That's not what that means at all. A static field just exists as a field once per type (or per combination of generic type arguments). That's all it means. When you pass the value of a static field to a method, the value from the static field is read once and copied onto the stack, and that copy is passed to the method. The value of the static field will not be changed during the call.
Perhaps the confusion here is actually "reference types", not "pass by reference"; if a static field is actually a reference to an object, then changes to the object will be observed by all callers. But it isn't the field that changed: it is the object.
Why is the code below
private static List<WorkflowVariableDataSet> MergeDatasetsListBranch(out List<WorkflowVariableDataSet> datasetsList)
{
if(datasetsList == null)
datasetsList=new List<WorkflowVariableDataSet>();
datasetsList=new List<WorkflowVariableDataSet>();
return datasetsList;
}
generating an error at the first if statement:
Out parameter 'datasetsList' might not be initialized before accessing.
I know it should be uninitialized at this point, but the word might suggest that the error lies in possible uninitialized object accessing (when it's not even accessed, it's the reference, that is checked). Ofc that doesn't happen with ref keyword, but I'm curious how is the reference checking violating out-parameters policy.
EDIT
I've edited the question and the example: the out object will be initialized inside the method anyway. The question is: WHY uninitialized object cannot be null compared? How is that different from:
object o;
if(o==null)
...
Compiler Error CS0269
Use of unassigned out parameter 'parameter' The compiler could not
verify that the out parameter was assigned a value before it was used;
its value may be undefined when assigned. Be sure to assign a value to
out parameters in the called method before accessing the value. If you
need to use the value of the variable passed in, use a ref parameter
instead.
So treat an out-parameter as unassigned. You are the one who is responsible.
So just remove the if:
datasetsList = new List<WorkflowVariableDataSet>();
If you want to process a list that is passed to this method use ref intead (as suggested above):
Because whether you've buggy code that never initialises the parameter, or buggy code that sometimes doesn't initialise it, it's still the same bug.
There's no point having a separate error message for the same bug depending on whether it hits in all or just one code paths; if there is a single code-path where the parameter is used before initialising, then it's has that error, and if there isn't a single code-path, then it doesn't.
So if we consider:
private static List<WorkflowVariableDataSet> MergeDatasetsListBranch(out List<WorkflowVariableDataSet> datasetsList)
{
if(_someBooleanField)
datasetsList = null;
if(datasetsList == null)
datasetsList=new List<WorkflowVariableDataSet>();
return datasetsList;
}
Here the use of an uninitialised out parameter might or might not happen, but that suffices to mean it has the same error.
As far as the error goes, there really isn't any significant difference between these two cases.
And therefore the error message uses might, even in cases where it will always apply.
Out arguments need not be initialized prior to being passed, the calling method is required to assign a value before the method returns.
Modified your code
private static List<WorkflowVariableDataSet> MergeDatasetsListBranch(out List<WorkflowVariableDataSet> datasetsList)
{
return datasetsList = new List<WorkflowVariableDataSet>();
}
Let's say you are debugging. At one point you are in Method A, which has a parameter foo of type Foo. Later on you are in Method B, which also takes a parameter foo of type Foo.
These two variables may well be the same Foo instance, but how do you tell? Because they are in different scope, you cannot call ReferenceEquals(). Is there some way you can obtain the actual memory location the variables point to so that you can tell if they are the instance?
I believe you can use the Make Object ID feature. More information on this can be found here, but to summarize:
Set a BreakPoint in your code where you can get to an object variable that is in scope.
Run your code and let it stop at the BreakPoint.
In your Locals or Autos Window, right-click the object variable (note the Value column) and choose "Make Object ID" from the context menu.
You should now see a new ID number (#) new in the Value column.
After you "mark" the object, you will see the assigned ID in the second call to Foo.
While in the debugger, you could store a reference to the object in the first method to a static field and then compare the variable in the second method to the static field.
well you could get a pointer to your variable but this requires to run in an unsafe block.
once you are "unsafed" you can declare a pointer to your Foo like this:
Foo* p = &myFoo;
this has been already discussed here in SO:
C# memory address and variable
As a development of Mark Cidade's suggestion, when inside the first method type the following into the immediate window:
var whatever = foo;
Then, when in the second method, type the following:
bool test = object.ReferenceEquals(whatever, foo);
The immediate window will display the result of the test.
However, CodeNaked's suggestion is better.
I think of DataGridView's as being memory hogs. Is it better to pass by value a datagridview or by reference? Should it even be passed at all?
Passing it by value or reference isn't going to matter from a memory stand point, because the DataGridView is a reference type, not a value type.
The type DataGridView is a reference type and hence it's not possible to pass the object by value. You can pass the reference to the object by value but that is a very small (typically pointer sized) value.
To add to Joseph's answer, All passing it by value does is create a new variable on the call stack in the called methods stack frame, and copy the address (in the Heap) of the DataGridView object into that variable for use by the called method. All this does is prevent the called method from assigning a new DataGridView object's address to the variable in the caller (calling method), and thus changing which dataGridView the caller will be pointing to.
You won't (need to) pass any Control very often
You cannot pass the object itself at all.
You can only pass the reference to an object, and doing so by value (the default) or by reference (ref parameter) has no impact on memory usage. It is a design decision but usually, certainly for Controls, you will pass the reference by value.