Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 31: Value type vs Reference type

Section 31.1: Passing by reference using ref keyword

From the documentation :

In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment. To pass a parameter by reference, use the ref or out keyword.

The di erence between ref and out is that out means that the passed parameter has to be assigned before the function ends.in contrast parameters passed with ref can be changed or left unchanged.

using System;

class Program

{

static void Main(string[] args)

{

int a = 20;

Console.WriteLine("Inside Main - Before Callee: a = {0}", a); Callee(a);

Console.WriteLine("Inside Main - After Callee: a = {0}", a);

Console.WriteLine("Inside Main - Before CalleeRef: a = {0}", a);

CalleeRef(ref a);

Console.WriteLine("Inside Main - After CalleeRef: a = {0}", a);

Console.WriteLine("Inside Main - Before CalleeOut: a = {0}", a); CalleeOut(out a);

Console.WriteLine("Inside Main - After CalleeOut: a = {0}", a);

Console.ReadLine();

}

static void Callee(int a)

{

a = 5;

Console.WriteLine("Inside Callee a : {0}", a);

}

static void CalleeRef(ref int a)

{

a = 6;

Console.WriteLine("Inside CalleeRef a : {0}", a);

}

static void CalleeOut(out int a)

{

a = 7;

Console.WriteLine("Inside CalleeOut a : {0}", a);

}

}

Output :

GoalKicker.com – C# Notes for Professionals

129

Inside Main - Before Callee: a = 20

Inside Callee a : 5

Inside Main - After Callee: a = 20

Inside Main - Before CalleeRef: a = 20

Inside CalleeRef a : 6

Inside Main - After CalleeRef: a = 6

Inside Main - Before CalleeOut: a = 6

Inside CalleeOut a : 7

Inside Main - After CalleeOut: a = 7

Section 31.2: Changing values elsewhere

public static void Main(string[] args)

{

var studentList = new List<Student>(); studentList.Add(new Student("Scott", "Nuke")); studentList.Add(new Student("Vincent", "King")); studentList.Add(new Student("Craig", "Bertt"));

// make a separate list to print out later

var printingList = studentList; // this is a new list object, but holding the same student objects inside it

//oops, we've noticed typos in the names, so we fix those studentList[0].LastName = "Duke"; studentList[1].LastName = "Kong"; studentList[2].LastName = "Brett";

//okay, we now print the list

PrintPrintingList(printingList);

}

private static void PrintPrintingList(List<Student> students)

{

foreach (Student student in students)

{

Console.WriteLine(string.Format("{0} {1}", student.FirstName, student.LastName));

}

}

You'll notice that even though the printingList list was made before the corrections to student names after the typos, the PrintPrintingList method still prints out the corrected names:

Scott Duke

Vincent Kong

Craig Brett

This is because both lists hold a list of references to the same students. SO changing the underlying student object propogates to usages by either list.

Here's what the student class would look like.

public class Student

{

public string FirstName { get; set; } public string LastName { get; set; }

public Student(string firstName, string lastName)

{

GoalKicker.com – C# Notes for Professionals

130

this.FirstName = firstName; this.LastName = lastName;

}

}

Section 31.3: ref vs out parameters

Code

class Program

{

static void Main(string[] args)

{

int a = 20;

Console.WriteLine("Inside Main - Before Callee: a = {0}", a); Callee(a);

Console.WriteLine("Inside Main - After Callee: a = {0}", a); Console.WriteLine();

Console.WriteLine("Inside Main - Before CalleeRef: a = {0}", a);

CalleeRef(ref a);

Console.WriteLine("Inside Main - After CalleeRef: a = {0}", a);

Console.WriteLine();

Console.WriteLine("Inside Main - Before CalleeOut: a = {0}", a); CalleeOut(out a);

Console.WriteLine("Inside Main - After CalleeOut: a = {0}", a); Console.ReadLine();

}

static void Callee(int a)

{

a += 5;

Console.WriteLine("Inside Callee a : {0}", a);

}

static void CalleeRef(ref int a)

{

a += 10;

Console.WriteLine("Inside CalleeRef a : {0}", a);

}

static void CalleeOut(out int a)

{

// can't use a+=15 since for this method 'a' is not intialized only declared in the method declaration

a = 25; //has to be initialized

Console.WriteLine("Inside CalleeOut a : {0}", a);

}

}

Output

Inside Main - Before Callee: a = 20

Inside Callee a : 25

Inside Main - After Callee: a = 20

Inside Main - Before CalleeRef: a = 20

Inside CalleeRef a : 30

Inside Main - After CalleeRef: a = 30

GoalKicker.com – C# Notes for Professionals

131

Inside Main - Before CalleeOut: a = 30

Inside CalleeOut a : 25

Inside Main - After CalleeOut: a = 25

Section 31.4: Assignment

var a = new List<int>(); var b = a;

a.Add(5);

Console.WriteLine(a.Count); // prints 1 Console.WriteLine(b.Count); // prints 1 as well

Assigning to a variable of a List<int> does not create a copy of the List<int>. Instead, it copies the reference to the List<int>. We call types that behave this way reference types.

Section 31.5: Di erence with method parameters ref and out

There are two possible ways to pass a value type by reference: ref and out. The di erence is that by passing it with ref the value must be initialized but not when passing it with out. Using out ensures that the variable has a value after the method call:

public void ByRef(ref int value)

{

Console.WriteLine(nameof(ByRef) + value); value += 4; Console.WriteLine(nameof(ByRef) + value);

}

public void ByOut(out int value)

{

value += 4 // CS0269: Use of unassigned out parameter `value' Console.WriteLine(nameof(ByOut) + value); // CS0269: Use of unassigned out parameter `value'

value = 4; Console.WriteLine(nameof(ByOut) + value);

}

public void TestOut()

{

int outValue1;

ByOut(out outValue1); // prints 4

int outValue2 = 10; // does not make any sense for out

ByOut(out outValue2); // prints 4

}

public void TestRef()

 

{

 

int refValue1;

 

ByRef(ref refValue1); // S0165

Use of unassigned local variable 'refValue'

int refValue2 = 0;

 

ByRef(ref refValue2); // prints

0 and 4

int refValue3 = 10;

 

ByRef(ref refValue3); // prints

10 and 14

}

 

The catch is that by using out the parameter must be initialized before leaving the method, therefore the following

GoalKicker.com – C# Notes for Professionals

132