Как установить свойство объекта по ссылке на элемент массива?

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

using System;

public class HelloWorld
{
    private static string[] s = new string[] { null };
    
    public static void Main(string[] args)
    {
        var a = new A();
        a.Value = s[0];
        Console.WriteLine ("value bef = " + a.Value);
        s[0] = "test";
        Console.WriteLine ("value aft = " + a.Value);
    }
    
    public class A
    {
        public string Value { get; set; }
    }
}

Когда я запускаю приведенный выше код, я получаю следующий результат:

value bef = 
value aft = 

Однако, поскольку C# работает со строками со ссылками, я ожидал, что результат будет таким:

value bef = 
value aft = test

Почему это не работает? Могу ли я сделать это на С#? Преобразование A.Value в класс или s в массив A на самом деле не вариант.

Почему бы вам не сохранить в массиве весь объект A, а не просто строку?

gunr2171 10.04.2024 01:49

Потому что ссылки на объекты в s должны быть общими. A имеет другие свойства, которыми нельзя поделиться. Например, var a и еще один var b могут указывать на s[0] для свойства Value. Но остальными свойствами A делиться не следует.

kovac 10.04.2024 02:00

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

Enigmativity 10.04.2024 04:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
90
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Код будет работать в такой форме:

public static void Main(string[] args)
{
    var a = new A();
    a.Value = ref s[0]; // <- ref
    Console.WriteLine("value bef = " + a.Value);
    s[0] = "test";
    Console.WriteLine("value aft = " + a.Value);
}

public ref struct A
{
    public ref string Value;
}

Хорошо... но не делай этого.

Joel Coehoorn 10.04.2024 03:41

Хммм, при этом любые изменения, внесенные в a.Value, будут напрямую влиять на значение s[0], по сути делая s[0] изменяемым через a.Value. Более предсказуемым способом было бы наличие частного поля-члена в классе A.

Jeremy Thompson 10.04.2024 04:15
Ответ принят как подходящий

поскольку C# работает со строками со ссылками, я ожидал...

Во время первого вывода на консоль s[0] и a.Value являются ссылочными переменными, которые содержат null для ссылочных значений.

Но это разные переменные, и не важно, что одна была инициализирована другой. Вы можете изменить ту или иную переменную, не меняя обе, поскольку a.Value дана пустая ссылка на null. Ему не дается ссылка на переменную s[0].

Итак, присвоив "test"s[0], вы изменили эту переменную, чтобы она ссылалась на новый строковый объект, но переменная a.Value по-прежнему имеет ту же ссылку null, что и раньше.

Также не имеет значения, является ли начальное значение null или фактическим строковым объектом. Результат в любом случае один и тот же.


Но что, если массив s содержит ссылки на наш класс A?

private static A[] s = new A[] { null };

Затем я немного изменю код, чтобы у нас было значение для работы:

var a = new A();
s[0] = a; // reversed the assignment
Console.WriteLine ("value bef = " + a.Value); // Shows "value bef = "
s[0].Value = "test"; // s[0] is an A object now, so we set it's property
Console.WriteLine ("value aft = " + a.Value); // Shows "value aft = test"

Итак, нам ясно, что мы могли бы также сделать это:

// create the object here
private static A[] s = new A[] { new A() };

A a = new A();
a.Value = s[0]; // but keep the original assignment
Console.WriteLine ("value bef = " + a.Value); // Shows "value bef = "
s[0].Value = "test";
Console.WriteLine ("value aft = " + a.Value); // Shows "value aft = test"

Для обоих из них показаны изменения. Причина в том, что оба s[0] и a относятся к одному и тому же объекту. Это по-прежнему разные переменные, но они ссылаются на один и тот же элемент. Затем мы меняем свойство этого единственного объекта, а не саму ссылку на объект. Это тот же объект, но с другим значением свойства, поэтому обе переменные по-прежнему будут показывать одинаковый результат.

Потому что объект String неизменяем.

s[0] = "test"; 

s[0] не будет изменен, а будет создан новый строковый объект в другом месте памяти.

a.Value по-прежнему указывает на исходный объект, который имеет значение null.

Другие вопросы по теме