Передача параметров.NET - ссылкой v/s значением

Я пытаюсь проверить свое понимание того, как C#/.NET/CLR рассматривает типы значения и ссылочные типы. Я считал столько объяснений противоречия I все еще

Это - то, что я понимаю сегодня, исправьте меня, если мои предположения являются неправильными.

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

Вторая часть - то, чем я являюсь самым смущенным.

Позволяет рассматривают простой класс под названием Человек.

У человека есть свойство под названием Имя.

Позволяет говорят, что я создаю экземпляр Человека в другом классе, мы назовем его UselessUtilityClass.

Рассмотрите следующий код:

class UselessUtilityClass
{
   void AppendWithUnderScore(Person p)
   {
     p.Name = p.Name + "_";
   }
}

и затем где-нибудь мы делаем:

Person p = new Person();
p.Name = "Priest";
UselessUtilityClass u = new UselessUtilityClass();
u.AppendWithUnderScore(p);

Человек является ссылочным типом при передаче UselessUtilityClass - это - то, куда я иду - гайки... ПЕРЕМЕННАЯ p, который является экземпляром ссылки Человека, передается ЗНАЧЕНИЕМ, что означает, когда я пишу p. Имя я буду видеть "Священника _"

И затем если я записал

Person p2 = p;

И я делаю

p2. Имя = "Не Священник";

И напишите имя p как ниже, я получу "Не Священника"

Console.WriteLine(p.Name) // will print "Not a Priest"

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

Мое понимание корректно?

Я думаю, что существует некоторое продолжение недоразумения, когда люди говорят, что Все объекты в.NET передаются Ссылкой, это не танцует джайв на основе того, что я думаю. Я мог быть неправым, вот почему я приехал в Накопители.

17
задан Jon Seigel 27 February 2010 в 03:47
поделиться

6 ответов

Типы значений, такие как int и т.д., живут на стеке. Типы ссылок живут на управляемой куче , однако если тип ссылки, например, имеет переменную instance типа double, то он будет жить вместе со своим объектом на куче

Нет, это неправильно. Корректным является утверждение: "Локальные переменные и формальные параметры типа value, которые не находятся ни непосредственно в итерационном блоке, ни в закрытых внешних переменных лямбда-метода или анонимного метода, выделяются на системном стеке исполняющего потока в реализации CLI от Microsoft и реализации C# от Microsoft".

Нет требования, чтобы любая версия C# или любая версия CLI использовала системный стек для чего-либо. Естественно, мы это делаем потому, что это удобная структура данных для локальных переменных и формальных параметров типа value, которые не находятся непосредственно в итерационном блоке или закрытых внешних переменных лямбда или анонимного метода.

См. мои статьи на эту тему для обсуждения (1) почему это реализация, и (2) какие преимущества мы получаем от этого выбора реализации, и (3) какие ограничения влечет за собой желание сделать этот выбор реализации в языковом дизайне.

http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

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

Сделайте глубокий вдох.

Переменная - это место хранения. Каждое место хранения имеет ассоциированный тип.

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

Место хранения, ассоциированным типом которого является тип значения, всегда содержит объект этого типа.

Значение переменной является содержимым места хранения .

ПЕРЕМЕННАЯ p, которая является экземпляром ссылки на Человека, передается через VALUE,

Переменная p является местом хранения. Она содержит ссылку на экземпляр Человека. Поэтому значение переменной является ссылкой на Человека. Это значение -- ссылка на экземпляр -- передается в callee. Теперь другая переменная, которую вы путано называете "p", содержит то же самое значение -- это ссылка на определенный объект.

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

void Foo(ref int x) { x = 10; }
...
int p = 3456;
Foo(ref p);

, что это означает "x - это псевдоним для переменной p". То есть, x и p - это два имени для одной и той же переменной. Так что каким бы ни было значение p, это также значение x, потому что это два имени для одного и того же места хранения.

Теперь понятно?

27
ответ дан 30 November 2019 в 11:44
поделиться

Типы значений, такие как int etc, живут на Стек, ссылочные типы живут на Управляемая куча, однако, если ссылка Тип например, имеет экземпляр Переменная типа двойной, она будет жить вместе с его объектом на куче

правильно.

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

Переменная P, которая является экземпляром Ссылка на человека передается Значение

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

Я думаю, что есть некоторое недоразумение продолжается, когда люди говорят все объекты В .NET пропускаются по ссылке

Да, это определенно недоразумение. Все параметры передаются по значению (если только вы не используете или из ключевых слов, чтобы пройти их посредством ссылки). Прохождение Ссылка не то же самое, что проходит посредством ссылки .

Ссылка представляет собой тип значения, что означает, что все, что вы когда-либо проходите в качестве параметров, являются типов ценностей. Вы никогда не проходите сам экземпляр объекта, всегда его ссылки.

8
ответ дан 30 November 2019 в 11:44
поделиться

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

//Reference type
class Foo {
    public int I { get; set; }
}

//Value type
struct Boo {
    //I know, that mutable structures are evil, but it only an example
    public int I { get; set; }
}


class Program
{
    //Passing reference type by value
    //We can change reference object (Foo::I can changed), 
    //but not reference itself (f must be the same reference 
    //to the same object)
    static void ClassByValue1(Foo f) {
        //
        f.I++;
    }

    //Passing reference type by value
    //Here I try to change reference itself,
    //but it doesn't work!
    static void ClassByValue2(Foo f) {
        //But we can't change the reference itself
        f = new Foo { I = f.I + 1 };
    }

    //Passing reference typ by reference
    //Here we can change Foo object
    //and reference itself (f may reference to another object)
    static void ClassByReference(ref Foo f) {
        f = new Foo { I = -1 };
    }

    //Passing value type by value
    //We can't change Boo object
    static void StructByValue(Boo b) {
        b.I++;
    }

    //Passing value tye by reference
    //We can change Boo object
    static void StructByReference(ref Boo b) {
        b.I++;
    }

    static void Main(string[] args)
    {
        Foo f = new Foo { I = 1 };

        //Reference object passed by value.
        //We can change reference object itself, but we can't change reference
        ClassByValue1(f);
        Debug.Assert(f.I == 2);

        ClassByValue2(f);
        //"f" still referenced to the same object!
        Debug.Assert(f.I == 2);

        ClassByReference(ref f);
        //Now "f" referenced to newly created object.
        //Passing by references allow change referenced itself, 
        //not only referenced object
        Debug.Assert(f.I == -1);

        Boo b = new Boo { I = 1 };

        StructByValue(b);
        //Value type passes by value "b" can't changed!
        Debug.Assert(b.I == 1);

        StructByReference(ref b);
        //Value type passed by referenced.
        //We can change value type object!
        Debug.Assert(b.I == 2);

        Console.ReadKey();
    }

}
1
ответ дан 30 November 2019 в 11:44
поделиться

Попробуйте выполнить команду Spring 3.0: Смотрите этот пост

-121--3787536-

Try/main\| ^, но если курсор в файле находится не в первой строке - это не то, что нужно.

-121--5086317-

В спецификациях ничего не говорится о том, где распределять типы значений и объекты. Правильная реализация C # - распределять все в куче, и в некоторых ситуациях Atr значения распределяются в куче, отличной от записанных.

int i = 4; Func dele = () = > (object) i;

Приведет к тому, что (копия) i будет выделена в куче, поскольку компилятор превратится в член класса, если он не будет объявлен как таковой. Кроме того, что ты в основном на месте. И никакое все не передается в качестве справочного. Ближе к толчку было бы указать, что каждый параметр был передан по значению, но все же не совсем корректен (например, ref или out).

0
ответ дан 30 November 2019 в 11:44
поделиться

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

Когда вы проходите Ref (с ключевым словом ref / out), это передает одинаковую ссылку на объект, который вы используете в вызывающем абонете, а не создать копию ссылки.

1
ответ дан 30 November 2019 в 11:44
поделиться

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

-121--3832498-

Термин «проход по значению» немного вводит в заблуждение.

Есть две вещи, которые вы делаете:

1) прохождение ссылочного типа (человек p) в качестве параметра к способу

2) Установка переменной типа референс (человек P2) к уже существующей переменной Человек P)

Давайте посмотрим на каждый случай.

Случай 1

Вы создали человека P, указывая на местоположение в памяти, давайте назовем это местоположение x. Когда вы переходите в метод AppendWithundersCore , вы выполняете следующий код:

p.Name = p.Name + "_"; 

Способ вызова «Создает новую локальную переменную P, то указываю на то же место в памяти: x. Итак, если вы измените P внутри вашего метода, вы будут изменить состояние с.

Однако внутри этого метода, если вы устанавливаете P = NULL , то вы нет NULL из P, снаружи способа. Такое поведение называется «Pass по значению»

Case 2

Этот случай аналогичен вышеуказанному случаю, но немного отличается. Когда вы создаете новую переменную P2 = P, вы просто говорите, что P2 ссылаются на объект в расположении с. Так что теперь, если вы измените P2, вы изменяете P, так как они ссылаются на тот же объект. Если вы сейчас говорите P2 = NULL, то P теперь будет также быть нулевым. Обратите внимание на разницу между этим поведением и поведением внутри вызова метода. Эта поведенческая разность описывает, как работает «проход по значению» при вызове методов

0
ответ дан 30 November 2019 в 11:44
поделиться
Другие вопросы по тегам:

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