C#不可变对象setter 理解
C# immutable object setter understanding
我有不可变的 class F1。我想改变其中一个领域。在设置方法中,我必须 return F1 class 的新实例进行更改。我不明白我该怎么做。
public class F1
{
public readonly int k1;
public readonly ImmutableList<int> k2;
public F1(int k)
{
...
}
public int GetItem(int pos)
{
return k2[pos];
}
public F1 SetItem(int pos, int val)
{
return new F1() // How i can create new instance with changes in pos
}
}
String.cs中有替换方法。字符串在 C# 中是不可变的 class(或者我认为是)。替换方法定义如下:
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private string ReplaceInternal(char oldChar, char newChar);
[__DynamicallyInvokable]
public string Replace(char oldChar, char newChar)
{
return this.ReplaceInternal(oldChar, newChar);
}
所以我不知道 ReplaceInternal 是如何工作的,因此找不到我的问题的答案。
假设您的构造函数如下所示:
public F1(int k1, ImmutableList<int> k2)
{
this.k1 = k1;
this.k2 = k2;
}
您可以创建方法来修改属性,方法是创建并返回具有已更改属性的新对象,而不是改变当前对象。
public F1 SetK1(int newk1)
{
return new F1(newk1, this.k2);
}
public F1 SetK2(ImmutableList<int> newK2)
{
return new F1(this.k1, newK2);
}
您的解决方案基于 String 的 Replace
方法,这可能不是最好的主意。 Whosebug 历史表明,人们,尤其是 .NET 框架的新手,经常误解 String.Replace
的语义,因为它的语法并不意味着不变性,你不得不依赖外部文档或先验知识。
我不会创建实际上不设置值的 setters/Set 方法,而是创建一个名为 "GetModifiedCopy" 的方法,它明确地 return 是一个具有修改值的新副本.这个
public class F1
{
public readonly int k1;
public F1(int k1)
{
...
}
public F1 GetModifiedCopy(int newVal)
{
return new F1(newVal);
}
}
现在,您的情况有点复杂,因为您不仅要实例化具有单个值的新实例,而且要复制整个现有列表并修改一个值。但是,解决方案是相同的——创建一个接收原始列表和新值的私有构造函数,在构造函数中修改列表,并 return 新实例。
private F1(ImmutableList<int> baseList, int pos, int value)
{
var tempList = baseList.ToList(); // create mutable list.
tempList[pos] = value; // modify list.
this.k2 = new ImmutableList<int>(tempList); // immutablize!
}
public F1 GetModifiedCopy(int pos, int value)
{
return new F1(this.k2, pos, value);
}
很难说出您究竟想在构造函数中做什么,但您可以添加另一个接受 ImmutableList 的构造函数(如 Kryzsztof 所示)并修改 SetItem 方法,如下所示:
public F1 SetItem(int pos, int val)
{
return new F1(k1, k2.SetItem(pos, val));
}
完整实施:
public class F1
{
public readonly int k1;
public readonly ImmutableList<int> k2;
public F1(int k)
{
...
}
private F1(int k1, ImmutableList<int> k2)
{
this.k1 = k1;
this.k2 = k2;
}
public int GetItem(int pos)
{
return k2[pos];
}
public F1 SetItem(int pos, int val)
{
return new F1(k1, k2.SetItem(pos, val));
}
}
请注意,我将新的构造函数设为私有,假设您不想出于此目的以外的任何目的公开此构造函数。
编辑:
我还应该注意,ImmutableList 的语义是这样的,即使用典型列表方法对列表进行的任何修改都会产生一个新列表,例如对 SetItem 的调用:
k2.SetItem(pos, val)
我有不可变的 class F1。我想改变其中一个领域。在设置方法中,我必须 return F1 class 的新实例进行更改。我不明白我该怎么做。
public class F1
{
public readonly int k1;
public readonly ImmutableList<int> k2;
public F1(int k)
{
...
}
public int GetItem(int pos)
{
return k2[pos];
}
public F1 SetItem(int pos, int val)
{
return new F1() // How i can create new instance with changes in pos
}
}
String.cs中有替换方法。字符串在 C# 中是不可变的 class(或者我认为是)。替换方法定义如下:
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private string ReplaceInternal(char oldChar, char newChar);
[__DynamicallyInvokable]
public string Replace(char oldChar, char newChar)
{
return this.ReplaceInternal(oldChar, newChar);
}
所以我不知道 ReplaceInternal 是如何工作的,因此找不到我的问题的答案。
假设您的构造函数如下所示:
public F1(int k1, ImmutableList<int> k2)
{
this.k1 = k1;
this.k2 = k2;
}
您可以创建方法来修改属性,方法是创建并返回具有已更改属性的新对象,而不是改变当前对象。
public F1 SetK1(int newk1)
{
return new F1(newk1, this.k2);
}
public F1 SetK2(ImmutableList<int> newK2)
{
return new F1(this.k1, newK2);
}
您的解决方案基于 String 的 Replace
方法,这可能不是最好的主意。 Whosebug 历史表明,人们,尤其是 .NET 框架的新手,经常误解 String.Replace
的语义,因为它的语法并不意味着不变性,你不得不依赖外部文档或先验知识。
我不会创建实际上不设置值的 setters/Set 方法,而是创建一个名为 "GetModifiedCopy" 的方法,它明确地 return 是一个具有修改值的新副本.这个
public class F1
{
public readonly int k1;
public F1(int k1)
{
...
}
public F1 GetModifiedCopy(int newVal)
{
return new F1(newVal);
}
}
现在,您的情况有点复杂,因为您不仅要实例化具有单个值的新实例,而且要复制整个现有列表并修改一个值。但是,解决方案是相同的——创建一个接收原始列表和新值的私有构造函数,在构造函数中修改列表,并 return 新实例。
private F1(ImmutableList<int> baseList, int pos, int value)
{
var tempList = baseList.ToList(); // create mutable list.
tempList[pos] = value; // modify list.
this.k2 = new ImmutableList<int>(tempList); // immutablize!
}
public F1 GetModifiedCopy(int pos, int value)
{
return new F1(this.k2, pos, value);
}
很难说出您究竟想在构造函数中做什么,但您可以添加另一个接受 ImmutableList 的构造函数(如 Kryzsztof 所示)并修改 SetItem 方法,如下所示:
public F1 SetItem(int pos, int val)
{
return new F1(k1, k2.SetItem(pos, val));
}
完整实施:
public class F1
{
public readonly int k1;
public readonly ImmutableList<int> k2;
public F1(int k)
{
...
}
private F1(int k1, ImmutableList<int> k2)
{
this.k1 = k1;
this.k2 = k2;
}
public int GetItem(int pos)
{
return k2[pos];
}
public F1 SetItem(int pos, int val)
{
return new F1(k1, k2.SetItem(pos, val));
}
}
请注意,我将新的构造函数设为私有,假设您不想出于此目的以外的任何目的公开此构造函数。
编辑: 我还应该注意,ImmutableList 的语义是这样的,即使用典型列表方法对列表进行的任何修改都会产生一个新列表,例如对 SetItem 的调用:
k2.SetItem(pos, val)