Строковый объект действительно ссылкой? [дубликат]

  Thrd 1 --- Lock A        - atmpt lock on B -   
         \                /                   \
          \              /                     \           
           \            /                       \         
            --- Lock A /                         --- wait for lock on B

  Thrd 2--- Lock B         - atmpt lock on A -   
         \                /                   \
          \              /                     \           
           \            /                       \         
            --- Lock B /                         --- wait for lock on A

Поток 1 запускается, блокирует A, делает что-то, и прерывается потоком 2, который блокирует B, делает что-то и прерывается потоком 1, который пытается заблокировать B, но поток 2 заблокировал B, так что поток 1 ожидает и прерывается потоком 2, который пытается заблокировать A, но поток 1 имеет блокировку на A, поэтому поток 2 должен ждать.

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

Тупик

14
задан abatishchev 12 December 2014 в 04:15
поделиться

10 ответов

Строка действительно является ссылочным типом. Однако, когда ваш метод Main вызывает changeMe (str), .NET передает копию ссылки на str на changeMe в аргументе param. changeMe затем изменяет эту копию так, чтобы она ссылалась на «Я изменил тебя !!!», но исходная ссылка на str по-прежнему указывает на «Я никогда не изменюсь».

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

20
ответ дан 1 December 2019 в 06:39
поделиться

Строки являются ссылками.

changeMe не изменяет строку, а просто переназначает локальную ссылку (указатель) внутри этой функции.

Теперь, если вы передали строка как ref arg, вы можете повеселиться:

public static string changeMe(ref string param) {
    param = "I have changed you!!!";
    return ""; // no return for test
}
13
ответ дан 1 December 2019 в 06:39
поделиться

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

Попробуйте вместо этого:

public static string changeMe(ref string param)
{
    param = "I have changed you!!!";

    return ""; // no return for test
}
4
ответ дан 1 December 2019 в 06:39
поделиться

Причина, по которой Program.changeMe (str) не устанавливает для str значение «Я изменил вас !!!» заключается в том, что, хотя строка является ссылочным типом, ссылки передаются по значению.

Таким образом, param является копией ссылки, она изменяется внутри области Program.changeMe (param), а затем отбрасывается в конце метода .

Ссылка str только копируется, а не изменяется на ссылку «Я изменил тебя !!!»

4
ответ дан 1 December 2019 в 06:39
поделиться

строки - это действительно особый случай. Они являются ссылочными типами, но ведут себя как типы значений. Это было сделано "ради простоты" командой разработчиков .Net.

Замечательная цитата: Это ссылочный тип Распространенное заблуждение, что строка - это тип значения. Это потому, что его неизменность (см. Следующий пункт) заставляет его действовать как тип значения. На самом деле он действует как обычный ссылочный тип. См. Мои статьи о передаче параметров и памяти для получения более подробной информации о различиях между типами значений и ссылочными типами.

From: http://www.yoda.arachsys.com/csharp/strings.html

2
ответ дан 1 December 2019 в 06:39
поделиться

Да, это кажется странным. Что происходит, так это то, что вы передаете ссылку на свою строку в параметре, но вы передаете ее по значению , т.е. вы создаете копию ссылки в параметре. Таким образом, когда вы переназначаете его в рамках своей функции, вы меняете только локальную копию вашей строковой ссылки метода changeMe ().

Подробнее об этом здесь: http://www.yoda.arachsys.com/csharp/parameters.html

1
ответ дан 1 December 2019 в 06:39
поделиться

Страница MSDN может помочь объяснить, почему это ссылочный тип.

Поскольку String представляет собой набор char ] s и наследуется от различных базовых классов Collection, это класс и, следовательно, ссылочный тип.

1
ответ дан 1 December 2019 в 06:39
поделиться

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

0
ответ дан 1 December 2019 в 06:39
поделиться

Если вы планируете изменить значение аргумента метода, вам действительно следует использовать ключевые слова «ref» или «out». В противном случае вы рискуете использовать запутанные методы, которые могут или не могут сделать то, что вы намереваетесь. Как отмечали другие, вы меняете значение строковой ссылки, а не экземпляр объекта. Чтобы увидеть, как это работает с другими классами, я написал небольшой пример

static void Main(string[] args)
{
    var str = "String";
    var obj = new MyObject() { Value = "Object" };

    Console.WriteLine(str); //String
    Console.WriteLine(obj); //Object

    ChangeMe(str);
    ChangeMe(obj);

    Console.WriteLine(str); //String
    Console.WriteLine(obj); //Object

    ChangeMeInner(obj);
    // this is where it can get confusing!!!
    Console.WriteLine(obj); //Inner 

    ChangeMe(ref str);
    ChangeMe(ref obj); 

    Console.WriteLine(str); // Changed
    Console.WriteLine(obj); // Changed

    Console.Read();
}
class MyObject
{
    public string Value { get; set; }
    public override string ToString()
    {
        return Value;
    }
}
static void ChangeMe(MyObject input)
{
    input = new MyObject() { Value = "Changed" };
}
static void ChangeMeInner(MyObject input)
{
    input.Value = "Inner";
}
static void ChangeMe(string input)
{
    input = "Changed";
}
static void ChangeMe(ref MyObject input)
{
    input = new MyObject() { Value = "Changed" };
}
static void ChangeMe(ref string input)
{
    input = "Changed";
}
0
ответ дан 1 December 2019 в 06:39
поделиться

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

-1
ответ дан 1 December 2019 в 06:39
поделиться
Другие вопросы по тегам:

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