C# Core 3.1 ByRef и ByVal - PullRequest
       69

C# Core 3.1 ByRef и ByVal

5 голосов
/ 19 марта 2020

Я хочу установить объект, равный другим значениям объекта в C# ядре, а не по ссылке!

x.len=10;
val y=x;
y.len=x.len*2;

Я ожидаю, что y.len будет установлен на 20 и x.len, чтобы остаться неизменным, но оба y.len и x.len являются 20 , я ищу способ отключить x и y.

Я помню, что в VB6 у нас было что-то вроде ByRef и ByVal , которое давало нам возможность контролировать эту вещь, есть ли подобное в C# Core 3.x

Ответы [ 2 ]

2 голосов
/ 19 марта 2020

Я хочу установить объект, равный другим значениям объекта в c# ядре, а не по ссылке!

Для этого либо вам нужен тип значения как структура, которая не размещается в куче или для ссылочного типа, вам нужна глубокая копия, а не мелкая копия. В. Net C# все классы по умолчанию размещены в куче, являются ссылочным типом, и когда объект передается, то либо его ссылка по значению (который является другим указателем на ту же память), либо ссылка по ссылке (указатель на указатель, который использует ключевые слова ref и out)

Давайте рассмотрим код

var y=x;, посмотрев на результат, можно предположить что оба y и x имеют одинаковый тип, но оба являются ссылочными типами. Поэтому, если value type не подходит для вас, выполните одно из следующих действий:

Создайте глубокую копию с помощью:

  1. Сериализация, предпочтительно двоичная как ее компактная, для некруглой иерархии объектов сериализация работает хорошо, когда вы десериализуете тогда ее новый объект
  2. Используйте конструктор копирования, где объект копируется свойство за свойством, поле за полем в свободное sh выделение

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

1 голос
/ 19 марта 2020

Самый простой способ «отсоединить» вещи - это, во-первых, быть типами значений; если x - это какое-то struct, то то, что у вас есть , будет работать уже , однако: изменяемые структуры обычно являются ужасной идеей и вызывают всевозможные недоразумения, поэтому в действительности я бы go с другим API там:

var x = new SomeReadonlyValueType(10);
var y = x; // this is a value copy
y = y.WithLength(x.len * 2); // mutation method

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

x.len=10;
val y=x.DeepClone();
y.len=x.len*2;

Здесь точка, где они становятся отдельными, очень ясна и явна; вам нужно будет реализовать DeepClone() - стандартного встроенного способа обеспечить это не существует. Для простых случаев хорошо подкатить вручную; для сложных случаев сериализация является популярным способом сделать это.


Пример кода для SomeReadonlyValueType:

readonly struct SomeReadonlyValueType
{
    public int Length { get; }
    public int Width { get; }
    public SomeReadonlyValueType(int length, int width)
    {
        Length = length;
        Width = width;
    }
    public override string ToString() => $"{Length} x {Width}";
    public SomeReadonlyValueType WithLength(int length)
        => new SomeReadonlyValueType(length, Width);
    public SomeReadonlyValueType WithWidth(int width)
        => new SomeReadonlyValueType(Length, width);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...