Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:不可变类_C#_Arrays_Class_Properties_Immutability - Fatal编程技术网

C#:不可变类

C#:不可变类,c#,arrays,class,properties,immutability,C#,Arrays,Class,Properties,Immutability,我有一个类在这个类中应该是不可变的,我只有一个私有的集合属性,所以为什么这不是不可变的,我可以在数组中设置一些字段,就像你们在主类中看到的一样 class ImmutableMatice { public decimal[,] Array { get; private set; } // immutable Property public ImmutableMatice(decimal[,] array) { Array = array;

我有一个类在这个类中应该是不可变的,我只有一个私有的集合属性,所以为什么这不是不可变的,我可以在数组中设置一些字段,就像你们在主类中看到的一样

class ImmutableMatice
{       
    public decimal[,] Array { get; private set; } // immutable Property

    public ImmutableMatice(decimal[,] array)
    {
        Array = array;
    }
    public decimal this[int index1, int index2]
    {
        get { return Array[index1, index2]; }
    }
。。。。。。。。 在main方法中,如果我用数据填充这个类并更改数据

    static void Main(string[] args)
    {
        decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
        ImmutableMatice matrix = new ImmutableMatice(testData);
        Console.WriteLine(matrix[0,0]); // writes 1
        testData[0, 0] = 999;
        Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should 
                                        // write 1 because class should be immutable?
    }
 }
有没有办法使这个类不可变

啊,是的,解决方案是将数组复制到构造函数中的新数组,如下所示:

    public ImmutableMatice(decimal[,] array)
    {
        decimal[,] _array = new decimal[array.GetLength(0),array.GetLength(1)];
        //var _array = new decimal[,] { };
        for (int i = 0; i < array.GetLength(0); i++)
        {
            for (int j = 0; j < array.GetLength(1); j++)
            {
                _array[i, j] = array[i, j];
            }
        }
        Array = _array;
    }
公共不可变矩阵(十进制[,]数组)
{
decimal[,]_array=新的decimal[array.GetLength(0),array.GetLength(1)];
//var_数组=新的十进制[,]{};
for(int i=0;i
类是不可变的,但其中的对象不是

拥有
public decimal[,]Array{get;private set;}
只会保证您无法将属性
Array
设置为
Array
的新实例,但它不会阻止您访问现有对象并更改其值(这些值不是不可变的)

您可能需要查看适当命名的类

正如@Mike所指出的,我第一次看过去:这有一个转折点,因为您是通过
testData
对象而不是通过
matrix
来访问值的。虽然原始点仍然存在,但更确切地说,您的问题是您正在更改传递其引用的基础对象中的值。您正在一起绕过
不可变属性
对象

前面提到的使用
ReadOnlyCollection
的解决方案仍然有效:通过在其周围创建此只读包装,以后将无法再对其进行更改。然而,只有当您实际按照预期的方式使用它时才会出现这种情况:通过
ImmutableMatice
,而不是通过您仍然有引用的基础集合

解决此问题的另一个解决方案是将原始数组的内容复制到另一个数组中,以将其与仍有引用的数组“断开”

为了说明这一点,考虑下面的样本。第一个示例演示了底层引用如何仍然受到影响,而第二个示例演示了如何通过将值复制到新数组来解决此问题

void Main()
{
    var arr = new[] { 5 };
    var coll = new ReadOnlyCollection<int>(arr);
    Console.WriteLine (coll[0]); // 5
    arr[0] = 1;
    Console.WriteLine (coll[0]); // 1
}

void Main()
{
    var arr = new[] { 5 };
    var arr2 = new int[] { 0 };
    Array.Copy(arr, arr2, arr.Length);
    var coll = new ReadOnlyCollection<int>(arr2);
    Console.WriteLine (coll[0]); // 5
    arr[0] = 1;
    Console.WriteLine (coll[0]); // 5
}
void Main()
{
var arr=new[]{5};
var coll=新的只读集合(arr);
Console.WriteLine(coll[0]);//5
arr[0]=1;
Console.WriteLine(coll[0]);//1
}
void Main()
{
var arr=new[]{5};
var arr2=newint[]{0};
Array.Copy(arr,arr2,arr.Length);
var coll=新的只读集合(arr2);
Console.WriteLine(coll[0]);//5
arr[0]=1;
Console.WriteLine(coll[0]);//5
}

类是不可变的,但其中的对象不是

拥有
public decimal[,]Array{get;private set;}
只会保证您无法将属性
Array
设置为
Array
的新实例,但它不会阻止您访问现有对象并更改其值(这些值不是不可变的)

您可能需要查看适当命名的类

正如@Mike所指出的,我第一次看过去:这有一个转折点,因为您是通过
testData
对象而不是通过
matrix
来访问值的。虽然原始点仍然存在,但更确切地说,您的问题是您正在更改传递其引用的基础对象中的值。您正在一起绕过
不可变属性
对象

前面提到的使用
ReadOnlyCollection
的解决方案仍然有效:通过在其周围创建此只读包装,以后将无法再对其进行更改。然而,只有当您实际按照预期的方式使用它时才会出现这种情况:通过
ImmutableMatice
,而不是通过您仍然有引用的基础集合

解决此问题的另一个解决方案是将原始数组的内容复制到另一个数组中,以将其与仍有引用的数组“断开”

为了说明这一点,考虑下面的样本。第一个示例演示了底层引用如何仍然受到影响,而第二个示例演示了如何通过将值复制到新数组来解决此问题

void Main()
{
    var arr = new[] { 5 };
    var coll = new ReadOnlyCollection<int>(arr);
    Console.WriteLine (coll[0]); // 5
    arr[0] = 1;
    Console.WriteLine (coll[0]); // 1
}

void Main()
{
    var arr = new[] { 5 };
    var arr2 = new int[] { 0 };
    Array.Copy(arr, arr2, arr.Length);
    var coll = new ReadOnlyCollection<int>(arr2);
    Console.WriteLine (coll[0]); // 5
    arr[0] = 1;
    Console.WriteLine (coll[0]); // 5
}
void Main()
{
var arr=new[]{5};
var coll=新的只读集合(arr);
Console.WriteLine(coll[0]);//5
arr[0]=1;
Console.WriteLine(coll[0]);//1
}
void Main()
{
var arr=new[]{5};
var arr2=newint[]{0};
Array.Copy(arr,arr2,arr.Length);
var coll=新的只读集合(arr2);
Console.WriteLine(coll[0]);//5
arr[0]=1;
Console.WriteLine(coll[0]);//5
}

这是因为您实际上是在更改数组中的数据,而不是索引器

static void Main(string[] args)
{
    decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
    ImmutableMatice matrix = new ImmutableMatice(testData);
    Console.WriteLine(matrix[0,0]); // writes 1
    testData[0, 0] = 999; // <--- THATS YOUR PROBLEM
    Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should 
                                    // write 1 because class should be immutable?
}

这是因为您实际上是在更改数组中的数据,而不是索引器

static void Main(string[] args)
{
    decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
    ImmutableMatice matrix = new ImmutableMatice(testData);
    Console.WriteLine(matrix[0,0]); // writes 1
    testData[0, 0] = 999; // <--- THATS YOUR PROBLEM
    Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should 
                                    // write 1 because class should be immutable?
}

此外,Seda可能应该使
公共十进制[,]数组{get;private set;}
完全私有/不可访问。@Chris是的,的确如此。索引器应该是私有数组对外的唯一暴露。此外,Seda可能应该使
公共十进制[,]数组{get;private set;}
完全私有/不可访问。@Chris是的,的确如此。索引器应该是私有数组对外的唯一暴露。这实际上只是它不是不可变的部分原因,事实上也不是示例不能按预期工作的原因。如果需要真正的不变性,则需要在构造函数中复制提供的数组