Using a reference value as parameter, with or without "ref"? [duplicate] - c#

This question already has answers here:
Why use the 'ref' keyword when passing an object?
(10 answers)
Closed 7 years ago.
I came accross two Solutions(both work):
public List<Label> foo1(ref ISomeInterface[] all)
or
public List<Label> foo2(ISomeInterface[] all)
Is there a diffrerence, does it matter which of them I take ? Interface is a reference value and will give the parameter as reference anyway and "ref" will also get the reference...I think I can dismiss "ref" ... I wonder why the compiler does not give me an error...

Is there a diffrerence?
Yes, there is. Everything in C# is passed by value. When you pass a reference type by ref, you pass the actual reference pointer rather then a copy. That way, if you pass a reference type by ref and set it to a new reference via the new keyword, you'll alter the reference.
An example:
public static void Main(string[] args)
{
ISomeInterface[] somes = new[] { new SomeConcreteType() }
Foo(somes);
Console.WriteLine(somes.Length) // Will print 1
Foo(ref somes);
Console.WriteLine(somes.Length) // Will print 0
}
public List<Label> Foo(ref ISomeInterface[] all)
{
all = new ISomeInterface[0];
}
public List<Label> Foo(ISomeInterface[] all)
{
all = new ISomeInterface[0];
}

In first case you replace "global" (out of method) parameter all. In second case you will replace local copy of all parameter.
public List<Label> foo1(ref ISomeInterface[] all)
{
all = new ISomeInterface[0]; //you will get empty array outside method
}
public List<Label> foo1(ISomeInterface[] all)
{
all = new ISomeInterface[0]; //you will get empty array only inside method
}

It depends on what you want to do with the array.
If you want to modify the value in the foo1 method and use those modifications outside of the foo1 method, you may want to use the ref type version
If you just want to use the returned List<Label> you should use the option without ref.

Related

Correct syntax to initialize static array [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
I have following code definig an array
public class PalphabetsDic
{
public static string[] PAlphCodes = new string[3] {
PAlphCodes[0] = "1593",
PAlphCodes[1] = "1604",
PAlphCodes[2] = "1740",
};
}
When I use this array
var text = PalphabetsDic.PAlphCodes[1]
Gives error:
The type initializer for 'Dota2RTL.PalphabetsDic' threw an exception.
---> System.NullReferenceException: Object reference not set to an instance of an object.
Please can someone help me on this?
Note that What is a NullReferenceException, and how do I fix it? covers arrays, but PAlphCodes = new string[3] should be setting it up to be not null.
When initializing the way you are you don't need to index the values:
public static string[] PAlphCodes = new string[] {
"1593",
"1604",
"1740",
};
To expand upon what Kennedy answered -- you can also use
public static string[] PAlphCodes = { "1593", "1604", "1740" };
The reference manual has a listing of all the possible ways -- but the one Kennedy suggested -- and this method -- are probably the most common.
https://msdn.microsoft.com/en-us/library/aa287601(v=vs.71).aspx
Indeed you've used strnage syntax to initialize array as pointed out in other answers and something like static string[] PAlphCodes = new []{"1","2","3"}; would fix the problem.
On why this actually compiles (which is somewhat surprising for most people):
You can use static fields to initialize other static fields, but surprisingly you can also refer to static field inside initialization if the field itself. So there is no compile time error.
It fails at run-time first with NullReferenceException because initialization of the array is not completed by the time it is used for first time - so PAlphCodes is null while array is created. But since this is part of class level initialization (as it is static filed) this exception also stops class instance creation and you get "The type initializer ...." wrapping NullReferenceException .
Note that in most cases such construct would not even compile. I.e.
using it in non-static field of local variable fails at compile time with
A field initializer cannot reference the non-static field, method, or property ...
public class PalphabetsDic
{
public string[] PAlphCodes = new string[3] {
PAlphCodes[0] = "1593", // error here and other lines
PAlphCodes[1] = "1604",
PAlphCodes[2] = "1740",
};
}

Does C# pass a List<T> to a method by reference or as a copy? [duplicate]

This question already has answers here:
Are arrays or lists passed by default by reference in c#?
(4 answers)
Closed 8 years ago.
Taking my first steps in C# world from C/C++, so a bit hazy in details. Classes, as far as I understood, are passed by reference by default, but what about eg. List<string> like in:
void DoStuff(List<string> strs)
{
//do stuff with the list of strings
}
and elsewhere
List<string> sl = new List<string>();
//next fill list in a loop etc. and then do stuff with it:
DoStuff(sl);
Is sl in this case passed by reference or is a copy made so that I'd need to redefine the worker function like void DoStuff(ref List<string> strs) to actually act on sl itself and not a copy?
It's passed by reference. List<T> is a class, and all class instances are passed by reference.
The behaviour is always the same: Passing by copying. In case the parameter is an object, the reference to the object is copied, so in fact you are working on the same object/list/whatever.
In addition to other answers it is very important to understand the behavior of ref
Here is some sample code for demonstration purpose
static void Main(string[] args)
{
List<string> lstStr = new List<string>();
lstStr.Add("First");
lstStr.Add("Second");
Alter(lstStr);
//Alter(ref lstStr);
Console.WriteLine("---From Main---");
foreach (string s in lstStr)
{
Console.WriteLine(s);
}
Alter2(ref lstStr);
Console.WriteLine("---From Main after passed by ref---");
foreach (string s in lstStr)
{
Console.WriteLine(s);
}
Console.ReadKey();
}
static void Alter(List<string> lstStr2)
{
lstStr2.Add("Third");
Console.WriteLine("----From Alter----");
foreach (string s in lstStr2)
{
Console.WriteLine(s);
}
lstStr2 = new List<string>();
lstStr2.Add("Something new");
Console.WriteLine("----From Alter - after the local var is assigned somthing else----");
foreach (string s in lstStr2)
{
Console.WriteLine(s);
}
}
static void Alter2(ref List<string> lstStr2)
{
lstStr2 = new List<string>();
lstStr2.Add("Something new from alter 2");
Console.WriteLine("----From Alter2 - after the local var is assigned new list----");
foreach (string s in lstStr2)
{
Console.WriteLine(s);
}
}
//----From Alter----
//First
//Second
//Third
//----From Alter - after the local var is assigned somthing else----
// Something new
// ---From Main---
// First
// Second
// Third
// ----From Alter2 - after the local var is assigned new list----
// Something new from alter 2
// ---From Main after passed by ref---
// Something new from alter 2
The underlying thing always is: value types are passed by value, and reference types are "passed by reference" (quoted because the value of the reference is actually passed by value, but most people ignore that for the sake of brevity).
The easiest way to reconcile the ref keyword against references is: reference types have their reference passed by value. This has the effect, in the standard case, of simply passing the reference to the list (and not the entire list) to the method.
The ref keyword, when used on a reference type, semantically passes a reference to the reference (I really struggle not to say "pointer to a pointer").
If your method were to re-assign the ref argument to a new object, the caller would also see this new assignment. Whereas without the ref keyword, the method would simply be re-assign their own local copy of the reference value and the caller would still have a reference to their original object.
The above explanation is shamelessly taken from Jon Skeet's article on the topic:
This difference is absolutely crucial to understanding parameter
passing in C#, and is why I believe it is highly confusing to say that
objects are passed by reference by default instead of the correct
statement that object references are passed by value by default.
The ref keyword is only needed if you intend to re-assign the argument and have that visible to the caller. In most cases you will find that it isn't needed. Your DoStuff can be re-written to remove it and still pass a reference to the list by value successfully:
void DoSomething(List<string> strs)
{
strs.Add("Hello");
}
The ref keyword in your method is redundant if you want to modify the original list: List<T> is a reference type (class in C#) and so will be passed to the method by reference; therefore the method will manipulate the original list.
When passing a Value Type, it will create a copy of the value itself.
When passing a Reference Type, it will create a copy of the reference.
Read more about Value and Reference Types in C#.
The list is passed by reference. What that means is actually that the strs variable inside the method refers to the same list as the sl variable outside the method.
If you would use ref, you can actually reassign the the sl variable inside the method.
strs = new List<string>()
would make sl point to the new list.
Since you're coming from C/C++: ref could be considered a 'safe pointer'. It is similar to using &strs
Its by reference. Not necesary to include "ref".
Best regards.

how a method with string as its parameter in C#

This below code compiles and works out as intended.
class MyClass1
{
public void test()
{
string one = "testString1";
Console.WriteLine("MyClass1: " + one);
new MyClass2().test(one);
Console.WriteLine(one); //again testString1 is printed.
}
}
class MyClass2
{
public void test(string two)
{
Console.WriteLine("Test method");
Console.WriteLine(two);
two = "pilot";
Console.WriteLine(two);
}
}
all I infer from this is:
The value assigned to the string in test method is local to that function and the changes will be reflected only if I use a ref or out.
The question is:
We all know that the string is a reference type (because it is of type, String)
So, for all the reference types : when passing around their objects, the changes should be reflected right ? (For ex, for the same example, if I pass around a object of a class, then any changes are reflected back right ?)
Why is this rule not followed here ?
Can any one point me in understanding what happens under the hood ?
Although strings are reference objects, they are also immutable. Since references are passed by value *, changes to variables representing the reference, are not reflected on the original.
To demonstrate the effect of passing reference objects, replace string with StringBuilder, and change the content inside the test method:
class MyClass1
{
public void test()
{
StringBuilder one = new StringBuilder("testString1");
Console.WriteLine("MyClass1: " + one);
new MyClass2().test(one);
Console.WriteLine(one); //testString1pilot is printed.
}
}
class MyClass2
{
public void test(StringBuilder two)
{
Console.WriteLine("Test method");
Console.WriteLine(two);
two.Append("pilot");
Console.WriteLine(two);
}
}
* Unless the method specifies a different mode of parameter passing, e.g. out or ref.
So, for all the reference types : when passing around their objects,
the changes should be reflected right ?
All reference types are passed by reference is not true.
all reference type or value types are passed by value by default.
if you want to pass any type as reference types you need to use ref or out keyword.
Note: String is a immutable type means Strings can not be changed.
That is the reason why you are not able to see the changes made in the called function.
You need to use StringBuilder to get back the changes.
JonSteek has explained about Parmeter passing well here
In your example, the fact that String is a reference type does not matter. The exact same thing would happen with any value type or even a mutable reference type (like a class).
This is because the parameter to a method normally acts like a local variable within the method. Changes made to the parameter are local to the method.
As you stated, the exception is when the parameter is ref or out.
You have to understand the difference between the string which is a reference type and the variable itself that points to that object.
two = "pilot";
When you do this, you are creating a new string object and telling variable two to now point to this new string. The variable one still points to the original string, which is a different object.

Ref vs No Ref for self-modifying objects

If the object being referenced as a parameter is being modified in a function, does it matter if you use ref or not? Is there a difference between the following two functions?
void DisposeObject(ClassThing c)
{
c.Dispose();
}
void DisposeObject(ref ClassThing c)
{
c.Dispose();
}
It doesn't matter. What matters is if you're assigning something to c (and want it reflected outside the method):
c = new ClassThing();
In that case you'd use ref.
It doesnt depend in your case.
BUT:
if you pass a reference object with the ref keyword you have inside of the method the possibility to change the reference to point to another Object of this type (so it will be visible outside of the method)
According to the MSDN guide to passing reference-type parameters:
When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref or out keyword.
So you can alter the original object, but you cannot change the original object to reference a different location in memory. Example:
static void Main()
{
int[] integerArray = new int[8];
foo(integerArray);
}
private void foo(int[] myArray)
{
myArray[0] = 5; //this changes integerArray
myArray = new int[4]; //this does not change integerArray,
// ... but it would if you used ref or out
}
So the difference does matter, although I don't know specifically about the behavior of Dispose().

What is the difference when passing by ref in a method and without ref in C#? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
When to pass ref keyword in
Hi All,
I am just surprised that why we have ref in C# while by default everything which is a reference type in C# is passed as a reference.
In simpler words, can anyone explain me the difference between these two method calls:
public void Test(SomeClass someClass)
{
// some code here
}
and
public void Test(ref SomeClass someClass)
{
// some code here
}
In my thinking they both have reference to same memory location.
So why do we need ref keyword at all ?
The ref keyword passes in a reference to whatever location is storing the reference. This allows you to manipulate this variable from the called function. This is particularly useful for value types, but also has uses when used with reference types. (Dictionary.TryGetValue() being a good example. The out parameter is required to return the value stored in the dictionary. out is equivalent to ref except that it will undergo a different set of compile-time checks.)
For example:
public void Test(ref SomeClass obj)
{
obj = null;
}
public void Test2(SomeClass obj)
{
obj = null;
}
public void Foo()
{
SomeClass obj = new SomeClass();
Test(ref obj);
// obj is null here!
obj = new SomeClass();
Test2(obj);
// obj is not null here.
}
I am just surprised that why we have ref in C# while by default everything is which is a reference type in C# is passed as a reference.
Because some things in C# are value types, and sometimes we want to pass those. We have the ref keyword so that those things can be passed by reference also.
It's analogous to the difference between a SomeClass * and a SomeClass ** in C++.
With a SomeClass * (or without ref), we can modify the object pointed to, but we can't redirect it to an entirely new object.
With a SomeClass ** (or with ref), we can change the argument in the calling code in order to point it to an object of our choosing.
When you pass an object you pass it by reference. This means that anything you do to that object will be reflected in the object after the method returns. When you pass the reference by reference i.e. void Foo(ref object obj) you are passing the address of that object. You can then re-assign the address to a different object and that will be the state of things when the method returns
foo (object o)
{
...
}
var v = new object();
foo(v);
v will still reference the same object that was instantiated prior to the call to foo
void bar(ref object o)
{
o = null;
}
var v = new object();
foo(ref v);
// v is now null
Suppose method Foo accepts a Bar by value. If I have a Bar called "Boz", the statement:
Foo(Boz);
may take the object pointed to by Boz and change that object's characteristics, but it cannot change which object Boz points to. By contrast, if Boz were passed by reference, the same statement could cause Boz to point to a different object entirely.
As an example of usage, consider a routine that accepts an array as a parameter. If an array is passed by value, the recipient can change the value of any of the items in the array, but the recipient cannot change the size. The only way to change the size of an array is to create a new array, copy the old items into it, and from thence forth use the new array instead of the old one. When an array passed by value, there is no way for the recipient to tell the caller that it should stop using the old array and use the new one instead. With an array passed by reference that is not a problem.

Categories

Resources