Передача массива по значению в c# - PullRequest
0 голосов
/ 07 февраля 2020

Насколько я понимаю, тип или аргумент по умолчанию, передающие c#, являются значениями. Поэтому никаких заявлений не требуется. Но когда я пытаюсь выполнить следующий код, моя матрица A в Main изменяется с помощью операций, выполняемых для dMatrixU в методе Factorize() класса Decomposition. Я уверен, что проблема в конструкторе Decomposition, когда я просто назначаю A на dMatrixU, вместо значений присваивается ссылка A. Поэтому мой вопрос о том, как этого избежать, все, что я нашел, это как передать аргументы по ссылке. Опять же, как я понимаю, для передачи аргумента по значению модификатор не требуется. Где я не прав?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using LinearEquations;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            double[,] A = new double[,]
              { { 1, 1, 1  }  ,
                { 4, 3, -1 }  ,
                { 3, 5, 3  } };
            double[] B = new double[] {1,6,4};
            Decomposition lu = new Decomposition(A,B);
            lu.Factorize();
            PrintMatrix(A,"A:");
            PrintVector(B,"B:");
            PrintMatrix(lu.L,"L:");
            PrintMatrix(lu.U,"U:");
            PrintVector(lu.D,"D:");
        }
        public static void PrintMatrix(double[,] M, String Title = "Matrix: ")
        {
            Console.WriteLine(Title);
            for(int i = 0; i<M.GetLength(0); i++)
            {
                for(int j = 0; j<M.GetLength(1);j++)
                {
                    Console.Write(M[i,j]+"\t");
                }
                Console.Write("\n");
            }
            Console.Write("\n");
        }
        public static void PrintVector(double[] V, String Title = "Vector: ",bool AsRow = true)
        {
            String str = (AsRow)? "\t" : "\n";
            Console.WriteLine(Title);
            for(int i = 0; i<V.GetLength(0); i++)
            {
                Console.Write(V[i]+str);
            }
            Console.WriteLine("\n");
        }
    }
}

namespace LinearEquations
{
    public class Decomposition
    {
        // Fields
        private double[,] dMatrixA;  // Parameter in A*X=B
        private double[] dVectorB;  // Parameter in A*X=B
        private double[] dVectorX;  // Result wanted in A*X=B
        private double[,] dMatrixU; // A splits into L and U
        private double[,] dMatrixL; // L is used to calculate D in L*D=B
        private double [] dVectorD; // D is used to calculate X in U*X=D

        // Properties
        public double[,] A
        {
            get { return dMatrixA; }
            set { dMatrixA = value; }
        }
        public double[] B
        {
            get { return dVectorB; }
            set { dVectorB = value; }
        }
        public double[] X
        {
            get { return dVectorX; }
            set { dVectorX = value; }
        }
        public double[,] L
        {
            get { return dMatrixL; }
            set { dMatrixL = value; }
        }
        public double[,] U
        {
            get { return dMatrixU; }
            set { dMatrixU = value; }
        }
        public double[] D
        {
            get { return dVectorD; }
            set { dVectorD = value; }
        }

        // Constructor
        public Decomposition(double[,] A, double[] B)
        {
            dMatrixA = A;
            dVectorB = B;
            dVectorX = new double[B.Length];
            dMatrixU = A;
            dMatrixL = new double[A.GetLength(0),A.GetLength(1)];
            dVectorD = new double[B.Length];
        }

        // Split A into L and U
        public void Factorize()
        {
            // Iterate per each row
            for(int i = 0; i<dMatrixU.GetLength(0); i++)
            {
                // For all the rows make element i equals 0
                for(int j = i+1; j<dMatrixU.GetLength(0);j++)
                {
                    // Factor that assures substraction makes 0
                    dMatrixL[1,1] = dMatrixU[j,i] / dMatrixU[i,i];

                    // Iterate per each column
                    for(int k = 0; k<dMatrixU.GetLength(1);k++)
                    {
                        dMatrixU[j,k] = dMatrixU[j,k] - dMatrixU[i,k]*dMatrixL[1,1];
                    }
                }
            }
        }

    }
}

1 Ответ

2 голосов
/ 07 февраля 2020

Насколько я понимаю, тип или аргумент по умолчанию, передающий c#, является значением.

К сожалению, он немного сложнее и также имеет некоторые исключения:

Типы ссылок, такие как Decomposition, которые вы вручаете, делая копию ссылки. К сожалению, это означает, что оба все еще ссылаются на один и тот же экземпляр в памяти . Поэтому, несмотря на операцию копирования, это вызов по ссылке.

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

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

Ваш конкретный c case

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

В вашем случае у вас есть массивы типов значений. Если вы хотите избежать побочных эффектов при вызове по ссылке, эти массивы должны быть клонированы. Однако, поскольку double является типом значения, это клонирование может быть поверхностным . Нет необходимости в глубоком клонировании.

В отличие от Java, здесь нет специального метода Clone (). И я не уверен, почему именно. Однако вы часто можете использовать одну коллекцию для инициализации другой через конструктор. Или у них даже есть функция, подобная Array.Copy(), как указал TheBatman.

...