c#中按值传递数组
Passing array by value in c#
据我了解,传入c#
的默认类型或参数是按值传递的。因此不需要声明。但是当我尝试 运行 下面的代码时,我在 Main 中的 A
矩阵正在被 class 的 Factorize()
方法中对 dMatrixU
所做的操作修改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];
}
}
}
}
}
}
As far is i understand, the default type or argument passing in c# is by value.
不幸的是,它有点复杂,也有一些例外:
参考类型,如 Decomposition
您通过复制参考提交。不幸的是,这意味着两者仍然引用内存中 相同的实例 。所以尽管有复制操作,但它是按引用调用。
对于 Int
或 double
等值类型及其别名,通常会制作一个副本。我不知道在任何情况下它都没有,但我以前在那些事情上是错的。所以它们是按值调用的。
最后 String
和其他一些引用类型在设计上是不可变的。这样做的好处是它们在这方面的行为有点像值类型。你递交了一个Reference,但是实例本身是不能改变的。该代码只能在内存中创建一个具有不同值的新实例。因此,尽管移交了文字引用,但它有点像按值调用。
您的具体情况
数组是非常明确的引用类型。将它们交给一个没有副作用的函数,需要适当的克隆。如果是引用类型数组,克隆一定要深
在你的例子中,你有值类型数组。如果你想避免引用调用的副作用,你必须克隆那些数组。然而,由于 double 是一种值类型,this cloning can be shallow。无需深度克隆。
与 Java 不同,没有专门的 Clone() 方法。我不确定为什么。但是,您通常可以使用一个 Collection 通过构造函数初始化另一个 Collection。或者他们甚至有像 TheBatman 指出的 Array.Copy()
这样的功能。
据我了解,传入c#
的默认类型或参数是按值传递的。因此不需要声明。但是当我尝试 运行 下面的代码时,我在 Main 中的 A
矩阵正在被 class 的 Factorize()
方法中对 dMatrixU
所做的操作修改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];
}
}
}
}
}
}
As far is i understand, the default type or argument passing in c# is by value.
不幸的是,它有点复杂,也有一些例外:
参考类型,如 Decomposition
您通过复制参考提交。不幸的是,这意味着两者仍然引用内存中 相同的实例 。所以尽管有复制操作,但它是按引用调用。
对于 Int
或 double
等值类型及其别名,通常会制作一个副本。我不知道在任何情况下它都没有,但我以前在那些事情上是错的。所以它们是按值调用的。
最后 String
和其他一些引用类型在设计上是不可变的。这样做的好处是它们在这方面的行为有点像值类型。你递交了一个Reference,但是实例本身是不能改变的。该代码只能在内存中创建一个具有不同值的新实例。因此,尽管移交了文字引用,但它有点像按值调用。
您的具体情况
数组是非常明确的引用类型。将它们交给一个没有副作用的函数,需要适当的克隆。如果是引用类型数组,克隆一定要深
在你的例子中,你有值类型数组。如果你想避免引用调用的副作用,你必须克隆那些数组。然而,由于 double 是一种值类型,this cloning can be shallow。无需深度克隆。
与 Java 不同,没有专门的 Clone() 方法。我不确定为什么。但是,您通常可以使用一个 Collection 通过构造函数初始化另一个 Collection。或者他们甚至有像 TheBatman 指出的 Array.Copy()
这样的功能。