2009-11-08 5 views
0

Если кто-то передает объект методу с использованием ключевого слова 'Ref', то в чем разница с его передачей без ключевого слова ref?Объекты C# по ссылке

Потому что оба дают тот же результат, что объект был изменен при передаче управления обратно вызывающему объекту.

Такие, как это:

class Student 
{ 
    public string Name 
    { 
     get; 
     set; 
    } 

    public int Age 
    { 
     get; 
     set; 
    } 
} 
class Program 
{ 
    static Student student = new Student(); 
    static void Main(string[] args) 
    { 

     student.Age = 30; 
     student.Name = "StudentA"; 

     Console.WriteLine("Original Student: {0}, Age: {1}", student.Name, student.Age); 

     SetStudent(ref student); 

     Console.WriteLine("Student by Ref {0}, Age{1}", student.Name, student.Age); 

     AnotherStudent(student); 

     Console.WriteLine("Just Another Student {0}, Age {1}", student.Name, student.Age); 
     Console.ReadLine(); 
    } 

    public static void SetStudent(ref Student student) 
    { 
     student.Age = 16; 
     student.Name = "StudentY"; 
    } 

    public static void AnotherStudent(Student studenta) 
    { 
     if (studenta.Equals(student)) 
     { 
      Console.WriteLine("The same object in memory"); 
     } 
     studenta.Age = 12; 
     studenta.Name = "StudentX"; 
    } 
} 

Когда объект студент передается AnotherStudent() она будет изменена, событие думали, что это не прошло мимо «Ref».

Может кто-нибудь объяснить, что здесь происходит?

EDIT

Так что разница в передаче указателя на объект в C++ в функции?

Тони

+0

И в чем разница с передачей указателя на объект в C++? –

+0

Не могу конкурировать с * Пони * (я связываю его статью как ссылку), но у меня есть краткое сравнение с C++ в моем ответе. – JohnIdol

ответ

6

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

using System; 
using System.Text; 

class Test  
{  
    static void PassByValue(StringBuilder x) 
    { 
     x.Append(" - Modified object in method"); 
     x = new StringBuilder("New StringBuilder object"); 
    } 

    static void PassByReference(ref StringBuilder x) 
    { 
     x.Append(" - Modified object in method"); 
     x = new StringBuilder("New StringBuilder object"); 
    } 

    static void Main() 
    { 
     StringBuilder builder = new StringBuilder("Original"); 
     PassByValue(builder); 
     Console.WriteLine(builder); 

     builder = new StringBuilder("Original"); 
     PassByReference(ref builder); 
     Console.WriteLine(builder); 
    } 
} 

В обоих случаях, оригинальный StringBuilder модифицировал его содержимое, а затем параметрприсваивается новое значение. В случае «pass by value» это не изменяет значение переменной builder в Main.В случае «пройти по ссылке», значение builder относится к новому StringBuilder, поэтому результаты:

Original - Modified object in method 
New StringBuilder object 

В вашем случае, вы не видите никакой разницы с или без ref, потому что вы не изменяя значение самого параметра - только данные в объекте, к которому он относится.

Для получения дополнительной информации см. Мой article on parameter passing.

+1

простые смертные могут просто поклониться Тони Пони ;-) – JohnIdol

+0

Ах, спасибо за это. Думаю, я был близок к моему ответу. – Scott

3

Try переназначение объект студент, а не устанавливая его свойства.

public static void SetStudent(ref Student student) 
{ 
    student = new Student(); 
    student.Age = 16; 
    student.Name = "StudentY"; 
} 

public static void AnotherStudent(Student studenta) 
{ 
    studenta = new Student(); 
    studenta.Age = 12; 
    studenta.Name = "StudentX"; 
} 

Не думайте о ref как «передача по ссылке», потому что все ссылочные типы передаются по ссылке. Подумайте об этом как «ссылка на этот объект может быть переназначена»

+2

Нет, все ссылочные типы * не * передаются по ссылке. Вы ошибаетесь, «передавая ссылку» для «передачи ссылки». Это отдельные концепции, и их смешивание только усиливает путаницу. – Guffa

+0

Типы ссылок не передаются по ссылке - это распространенное заблуждение. Ссылка на объект копируется и эта копия передается методу (который фактически является передачей по значению). Ключевое слово 'ref' * означает * означает прохождение по ссылке - это означает, что сама ссылка передается, а не копия этой ссылки. –

+0

Это то, что я пытаюсь сделать. Кажется, что «пройти по ссылке» является слишком общим, я считаю, что именно поэтому этот вопрос был задан. – Bob

0

Когда вы передаете объект методу с использованием ключевого слова ref, вызываемый метод может обновить саму ссылку, а не только объект. Это означает, что в следующем фрагменте кода:

object a = new object(); 
SomeMethod(ref a); 

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

+0

Итак, если я правильно его использую с помощью Ref, можно изменить экземпляр в вызывающем методе, иначе использует тот же экземпляр, что и перед вызывающим методом? –

+1

@Tony: метод всегда может создать новый экземпляр и назначить его параметру. Однако вызывающий код не видит этот новый экземпляр, если вызов не выполняется с использованием ключевого слова 'ref'. –

0

Реальная разница станет очевидной, когда вы это делаете ...

public static void SetStudent(ref Student student) 
{ 
    student = new Student { Age = 69, Name="Botox" }; 
} 
... 
var a = new Student() 
var b = a; 
SetStudent(ref a); 
object.ReferenceEquals(a, b) // Should be false 
0

Эти примеры иллюстрирует разницу

methodA(ref object a) 
{ 
     a = new object(); 
} 

methodB(object a) 
{ 
    a = new object(); 
} 

object c = new object(); 
methodA(ref c); //now c points to an entire new object 
methodB(c); // does not change the value of c 
2

Попробуйте изменить два метода учащемуся:

public static void SetStudent(ref Student student) 
{ 
    student = new Student(); 
    student.Age = 16; 
    student.Name = "StudentY"; 
} 

public static void AnotherStudent(Student studenta) 
{ 
    studenta = new Student(); 
    studenta.Age = 12; 
    studenta.Name = "StudentX"; 
} 

Вызов SetStudent теперь будет изменить статическую переменную студента ссылаться на новый экземпляр, поскольку он передается как ref. Вызов AnotherStudent не изменит ссылку.

2

Я ограничиваю обсуждение ссылочными типами (все, что является классом, то есть я не говорю о структурах или встроенных типах значений). Для полного и подробного обсуждения вы можете посмотреть this link here.

Если вы передаете ссылочных типов без рефов ключевого слова вы передавая ссылку на значении, а это означает, что копия справки будет. На этом этапе вы можете изменить объект, на который указывает ref, BUT , если вы меняете другой объект (присваивая объекту ref, который вы передали в каком-либо другом объекте, который вы создаете), когда функция возвращает исходный объект , который находится за пределами функция, которую вы передали, все еще указывает на ту же старую ссылку.

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

Как вы указываете, в обоих случаях вы сможете изменить свой объект. В основном передача по ссылке в C# соответствует передаче простого указателя в C++, а передача без ключевого слова ref соответствует передаче указателя константы в C++ (вы можете вносить изменения, но не можете указать на smt else).

+0

Я думаю, что я в основном согласен с вами, но «во плоти и костях» не особенно ясен. IMO - я думаю, что говорить о аргументе (обычно переменном) яснее, чем ссылку в этом случае. –

+0

спасибо, я немного переформулировал – JohnIdol

1

Передача переменной по ссылке и передача ссылочного типа - это две разные вещи. Вы можете объединить их, передав ссылочный тип varaible по ссылке.

Передача переменной по ссылке означает, что метод может изменять переменную. Метод получает доступ к самой переменной, а не только к копии значения. Переменная не должна быть ссылочным типом, который должен быть передан по ссылке. Несколько случаев, когда используется пересылка по ссылке, на самом деле в основном относятся к типам значений.

При передаче ссылочного типа по ссылке это означает, что метод получает доступ к ссылочной переменной, а не только к копии ссылки на объект. Этот метод не только имеет доступ к объекту, но также может заменить ссылку в переменной ссылкой на другой объект.

Передача по ссылке редко необходима, и, конечно же, не то, что вам нужно сделать только потому, что вы передаете ссылочный тип в качестве параметра.