Я пытаюсь указать значение свойства элементу массива, который будет установлен позже. У меня есть следующий код:
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 на самом деле не вариант.
Потому что ссылки на объекты в s должны быть общими. A имеет другие свойства, которыми нельзя поделиться. Например, var a и еще один var b могут указывать на s[0] для свойства Value. Но остальными свойствами A делиться не следует.
Ссылка на строку — это просто переменная, подобная целому числу. Это значение, но оно представляет местоположение. Две переменные могут иметь одну и ту же ссылку, но когда вы меняете ссылку на одну из переменных, вы меняете только эту одну переменную. Другая ссылка остается прежней.





Код будет работать в такой форме:
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;
}
Хорошо... но не делай этого.
Хммм, при этом любые изменения, внесенные в a.Value, будут напрямую влиять на значение s[0], по сути делая s[0] изменяемым через a.Value. Более предсказуемым способом было бы наличие частного поля-члена в классе A.
поскольку 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.
Почему бы вам не сохранить в массиве весь объект
A, а не просто строку?