2014-05-06 2 views
11

Принимая мои первые шаги в C# мире от C/C++, так что немного туманно в деталях. Классы, насколько я понял, передаются по ссылке по умолчанию, но как насчет, например. Список < строка > как в:Предоставляет ли C# список <T> методу по ссылке или в качестве копии?

void DoStuff(List<string> strs) 
{ 
    //do stuff with the list of strings 
} 

и в других местах

List<string> sl = new List<string>(); 
//next fill list in a loop etc. and then do stuff with it: 
DoStuff(sl); 

Является С.Л. в этом случае передается по ссылке или копия сделана так, что мне нужно переопределить функцию уборщица, как

void DoStuff(ref List<string> strs)
, чтобы фактически действовать на sl сам, а не копией?

+6

'class' передается по Справка. 'struct' передается по значению. – Dialecticus

+1

Если вы ищете ссылку «C# list reference или value», вы найдете еще несколько полезных сообщений, например [this] (http://stackoverflow.com/questions/3473552/c-sharp-should-i-use- ref-to-pass-a-collection-eg-list-by-reference-to-a) и [this] (http://stackoverflow.com/questions/967402/are-arrays-or-lists-passed-by -default по ссылке-в-с). –

+0

[this] (http://yoda.arachsys.com/csharp/parameters.html) статья должна помочь вам лучше понять эту область. – Kurubaran

ответ

10

Он передан по ссылке. List<T> - это класс, и все экземпляры классов передаются по ссылке.

1

Ключевое слово ref в вашем методе является избыточным, если вы хотите изменить исходный список: List<T> является ссылочным типом (class на C#) и поэтому будет передан методу по ссылке; поэтому метод будет управлять исходным списком.

При передаче Value Type оно создаст копию самого значения. При передаче Reference Type он создаст копию справки.

Подробнее о Value and Reference Types в C#.

+4

'ref' не является избыточным. При этом 'strs = ...;' влияет на вызывающего. Без этого это не так. – delnan

+1

Кроме того, отправка объекта ссылочного типа методу без ключевого слова 'ref' приводит к созданию новой копии ссылки. «Резервный» означает, что это одно и то же. И это не так. – Tarec

7

Поведение всегда одно и то же: передача путем копирования. В случае, если параметр является объектом, ссылка на объект копируется, поэтому на самом деле вы работаете над одним и тем же объектом/списком/независимо.

4

Основой всегда является: типы значений передаются по значению, а ссылочные типы «передаются по ссылке» (цитируются, потому что значение ссылки фактически передается по значению, но большинство людей игнорируют это ради краткости).

Самый простой способ свести ключевое слово ref к ссылкам: ссылочные типы имеют ссылку, переданную по значению. Это означает, что в стандартном случае просто передать ссылку на список (а не весь список) на метод.

Ключевое слово ref, при использовании в ссылочном типе, семантически передает ссылку на ссылку (я действительно не могу сказать «указатель на указатель»).

Если ваш метод должен был повторно назначить аргумент ref новому объекту, вызывающий объект также увидит это новое назначение. Принимая во внимание, что без ключевого слова ref, метод просто перераспределит свою собственную локальную копию ссылочного значения, и вызывающий объект все равно будет иметь ссылку на свой исходный объект.

Приведенное выше описание бесстыдно взяты из Jon Skeet's article on the topic:

Это различие имеет решающее значение для понимания параметра переходящая в C#, и поэтому я считаю, что это сильно сбивает с толку, чтобы сказать, что объекты передаются по ссылке по умолчанию вместо правильного оператора ссылки на объекты по умолчанию передаются по значению.

Ключевое слово ref необходимо только в том случае, если вы намерены повторно назначить аргумент и иметь видимый для вызывающего абонента. В большинстве случаев вы обнаружите, что это не нужно. Ваш DoStuff может быть переписан, чтобы удалить его и до сих пор передать ссылку на список по значению успешно:

void DoSomething(List<string> strs) 
{ 
    strs.Add("Hello"); 
} 
+0

Это была моя первая «догадка» о том, как она будет работать, но была не совсем уверена. – Scre

+0

@scre Я настоятельно рекомендую прочитать статью Джона Скита, а также забрать книгу [C# in Depth] (http://www.manning.com/skeet2/), у которой есть хорошее умение структурировать объяснение абстрактных или сложные темы для удобного использования. –

-1

Сво по ссылке. Не обязательно включать «ref».

С уважением.

+3

'ref' не является избыточным. При этом 'strs = ...;' влияет на вызывающего. Без этого это не так. – delnan

+0

(Не требуется для эталонных значений) – fabian

2

Список передается по ссылке. Фактически это означает, что переменная strs внутри метода относится к тому же списку, что и переменная sl вне метода. Если вы используете ref, вы можете переназначить переменную sl внутри метода.

strs = new List<string>() 

сделает sl точкой в ​​новом списке.

Поскольку вы исходите из C/C++: ref может считаться «безопасным указателем». Это похоже на использование & STRs

4

В дополнение к другим ответам это очень важно, чтобы понять поведение исх

Вот некоторые примеры кода для демонстрационных целей

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 
Смежные вопросы