lPass значением и Передача Ссылкой

Вы могли объяснить следующее поведение Класса C#. Я ожидаю classResult как "Класс Lijo"; но фактическое значение “Изменяется”.

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

Все еще, почему значение изменяется?

public partial class _Default : Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        String nameString = "string Lijo";

        Person p = new Person();
        p.Name = "Class Lijo";

        Utilityclass.TestMethod(nameString, p);
        string classResult = p.Name;
        Response.Write(nameString + "....." + classResult);
    }
}

public class Utilityclass
{
    public static void TestMethod(String nameString, Person k)
    {
        nameString = "Changed";
        k.Name = "Changed";
    }
}

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

Обновление: Когда я передаю Строку, это не становится на самом деле измененным.

5
задан abatishchev 22 June 2013 в 03:27
поделиться

6 ответов

Самый краткий ответ: прочтите мою статью о передаче параметров , в которой это подробно рассматривается.

Более длинный ответ - сравнить эти два метода, оба из которых используют параметры value :

public void ChangeMe(string x)
{
    x = "changed";
}

public void ChangeMe(Person x)
{
    x.Name = "changed";
}

В первом случае вы изменяете значение параметра . Это полностью изолировано от исходного аргумента. Вы не можете изменить содержимое самой строки, потому что строки неизменяемы.

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

Если вы измените второй метод на этот:

public void ChangeMe(Person x)
{
    x = new Person("Fred");
}

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

Теперь, когда вы используете параметр ref , переменная, используемая вызывающей стороной в качестве аргумента, имеет "псевдоним" с параметром - поэтому, если вы измените значение параметра, это изменит значение аргумент также. Итак, если мы изменим последний метод следующим образом:

public void ChangeMe(ref Person x)
{
    x = new Person("Fred");
}

, затем:

Person y = new Person("Eric");
ChangeMe(ref y);
Console.WriteLine(y.Name);

, будет выведено «Fred».

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

22
ответ дан 18 December 2019 в 05:55
поделиться

Person является ссылочным типом, поэтому независимо от того, используете ли вы ref , out или ничего, вы всегда сможете изменить его внутри метода. Вы никогда не передаете объект реального человека методу, вы передаете указатель в качестве ссылки, но не фактическое Person . Ключевое слово ref полезно для типов значений (таких как структуры, int, float, DateTime, ...). Его также можно использовать со ссылочными типами, но только для указания поведения, но не для его принудительного применения. Если вы используете его со ссылочными типами, он позволяет вам изменить объект, на который указывает эта ссылка.

7
ответ дан 18 December 2019 в 05:55
поделиться

Когда вы передаете P методу тестирования, вы передаете его местоположение в памяти, а не копию объекта. Ссылка берется в теле метода, и исходное значение изменяется.

0
ответ дан 18 December 2019 в 05:55
поделиться

Utilityclass.TestMethod не может изменить локальную переменную p так, чтобы она указывала на другой объект Person , так как вы не передаете по ссылке, но по-прежнему можете вызывать любой методы или изменить какие-либо свойства переданного объекта. Таким образом, свойство Name можно изменить в Utilityclass.TestMethod .

0
ответ дан 18 December 2019 в 05:55
поделиться

Когда вы передаете аргумент ссылочного типа методу, это означает, что метод имеет прямой доступ к этому аргументу, а не к его копии ....

Таким образом, результат изменяется .

-1
ответ дан 18 December 2019 в 05:55
поделиться

На этот вопрос уже был дан ответ, но я думаю, что вы захотите попробовать этот фрагмент (бонусные очки, если вы попробуете это с ints!)

class Program
{
    static void Main(string[] args)
    {            
        Person p = new Person();
        p.Name = "Class Lijo";

        Utilityclass.TestMethod(p);
        string classResult = p.Name;
        Console.WriteLine(classResult);
        Utilityclass.TestMethod2(ref p);
        classResult = p.Name;  // will bomb here           
        Console.WriteLine(classResult);
    }
}

public class Utilityclass
{
    public static void TestMethod(Person k)
    {
        k.Name = "Changed";
        k = null;
    }

    public static void TestMethod2(ref Person k)
    {
        k.Name = "Changed Again!";
        k = null;
    }
}
0
ответ дан 18 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: