C# 那么';从外部代码的角度来看,它是不可变的?
更新:在发布了这个问题后,我突然想到,这个想法的主要缺点就是这种类型很容易被不当使用。也就是说,必须以非常具体的方式使用该类型才能获得任何好处。我最初想到的是这样使用的东西(为了保持一致性,坚持使用原始问题中的C# 那么';从外部代码的角度来看,它是不可变的?,c#,.net,struct,immutability,mutable,C#,.net,Struct,Immutability,Mutable,更新:在发布了这个问题后,我突然想到,这个想法的主要缺点就是这种类型很容易被不当使用。也就是说,必须以非常具体的方式使用该类型才能获得任何好处。我最初想到的是这样使用的东西(为了保持一致性,坚持使用原始问题中的SquareRootStruct示例): 所以,考虑到这很容易出错,我倾向于认为里德的观点(在他的评论中)可能是正确的,这对于一个班级来说更有意义 假设我有一个struct,我希望它具有以下特征: 从外部有利位置看是不变的 快速初始化 某些属性的延迟计算(和缓存) 显然,第三个特征意味着
SquareRootStruct
示例):
所以,考虑到这很容易出错,我倾向于认为里德的观点(在他的评论中)可能是正确的,这对于一个班级来说更有意义
假设我有一个
struct
,我希望它具有以下特征:
struct SquareRootStruct : IEquatable<SquareRootStruct>
{
readonly int m_value; // This will never change.
double m_sqrt; // This will be calculated on the first property
// access, and thereafter never change (so it will
// appear immutable to external code).
bool m_sqrtCalculated; // This flag will never be visible
// to external code.
public SquareRootStruct(int value) : this()
{
m_value = value;
}
public int Value
{
get { return m_value; }
}
public double SquareRoot
{
if (!m_sqrtCalculated)
{
m_sqrt = Math.Sqrt((double)m_value);
m_sqrtCalculated = true;
}
return m_sqrt;
}
public bool Equals(SquareRootStruct other)
{
return m_value == other.m_value;
}
public override bool Equals(object obj)
{
return obj is SquareRootStruct && Equals((SquareRootStruct)obj);
}
public override int GetHashCode()
{
return m_value;
}
}
struct SquareRootStruct:IEquatable
{
只读int m_value;//这永远不会更改。
double m_sqrt;//这将在第一个属性上计算
//访问权限,此后再也不会更改(因此它将
//对外部代码不可变)。
bool m_sqrtCalculated;//此标志将永远不可见
//外部代码。
public SquareRootStruct(int值):this()
{
m_值=值;
}
公共整数值
{
获取{返回m_值;}
}
公共双平方根
{
如果(!m_sqrtCalculated)
{
m_sqrt=数学sqrt((双)m_值);
m_sqrtCalculated=真;
}
返回m_sqrt;
}
公共布尔等于(SquareRootStruct其他)
{
返回m_值==其他.m_值;
}
公共覆盖布尔等于(对象对象对象)
{
返回obj为SquareRootStruct&&Equals((SquareRootStruct)obj);
}
公共覆盖int GetHashCode()
{
返回m_值;
}
}
现在,显然这是一个<强>平凡的例子,如<代码>数学。Sqrt < /COD>几乎不必花费太多代价,认为这种方法在这种情况下是值得的。这只是一个用于说明目的的示例
但我的想法是,这实现了我的三个目标,而最明显的替代方法无法实现这三个目标。具体而言:- 我可以在类型的构造函数中执行计算;但这可能无法实现上述第二个目标(快速初始化)
- 我可以对每个财产访问进行计算;但这可能无法实现上述第三个目标(缓存计算结果以备将来访问)
我是否遗漏了什么,或者这实际上是一个有价值的想法?这看起来类似于一个。有人提到在C#4.0并行扩展中更好地支持未来。(就像在正常工作的同时在另一个核心/线程上计算它们一样)。拥有内部使用变异的不可变数据结构没有错(只要线程安全性得到了充分宣传)。只是结构一直被复制,所以你不能做太多的变异。这在C/C++中不是问题,因为结构通常通过引用传递,而在C#中很少通过引用传递结构。由于很难对按值传递的结构进行推理,因此在C#中不鼓励使用可变结构。您所描述的可能会起到一定的作用,但有一个重要的警告:计算速度慢的结果在计算时可能会存储,也可能不会存储。例如,如果对枚举返回的结构执行计算,结果将存储在“临时”结构中,并将被丢弃,而不是传播回存储在数据结构中的结构中。我经常这样做。对我来说似乎很合理。我想你必须是某种FP纯粹主义者才会感到不满。@Kirk:是的,但问题变成了,“为什么你希望它是一个结构”而不是一个类?如果你真的在做计算值的“工作”,那么首先它真的是一个结构的候选者吗?@Reed Copsey:问题struct vs.class不是一个类型是否应该有值类型语义的问题,而不是你是否需要做任何内部计算吗?想想
DateTime
struct,它可以动态计算Year
或Day
属性。@OxA3:我认为这不是一个好的比较。DateTime只提供这些属性作为帮助程序-就像任何其他进行值类型转换的方法一样。在这种情况下,它不会对自己的内部状态做任何事情来让它工作。易变结构往往有奇怪的副作用,一旦你真的开始需要对它们进行变异(即使是为了惰性),我怀疑它们是否应该改为类。@Dan Tao:BTW-你可能想看看在类内部使用惰性来进行这种类型的操作-它给了你线程安全和非常简单的,
struct SquareRootStruct : IEquatable<SquareRootStruct>
{
readonly int m_value; // This will never change.
double m_sqrt; // This will be calculated on the first property
// access, and thereafter never change (so it will
// appear immutable to external code).
bool m_sqrtCalculated; // This flag will never be visible
// to external code.
public SquareRootStruct(int value) : this()
{
m_value = value;
}
public int Value
{
get { return m_value; }
}
public double SquareRoot
{
if (!m_sqrtCalculated)
{
m_sqrt = Math.Sqrt((double)m_value);
m_sqrtCalculated = true;
}
return m_sqrt;
}
public bool Equals(SquareRootStruct other)
{
return m_value == other.m_value;
}
public override bool Equals(object obj)
{
return obj is SquareRootStruct && Equals((SquareRootStruct)obj);
}
public override int GetHashCode()
{
return m_value;
}
}