更新:发布这个问题后,我想到这个想法的主要缺点只是这种类型很容易使用不当。也就是说,必须以非常特定的方式使用该类型才能获得任何好处。我最初想到的是可以像这样使用的东西(SquareRootStruct
为了保持一致性,坚持使用原始问题中的示例):
class SomeClass
{
SquareRootStruct _key;
public SomeClass(int value)
{
_key = new SquareRootStruct(value);
}
public double SquareRoot
{
// External code would have to access THIS property for caching
// to provide any benefit.
get { return _key.SquareRoot; }
}
public SquareRootStruct GetCopyOfKey()
{
// If _key has cached its calculation, then its copy will carry
// the cached results with it.
return _key;
}
}
// elsewhere in the code...
var myObject = new SomeClass();
// If I do THIS, only a COPY of myObject's struct is caching a calculation,
// which buys me nothing.
double x = myObject.GetCopyOfKey().SquareRoot;
// So I would need to do this in order to get the benefit (which is,
// admittedly, confusing)...
double y = myObject.SquareRoot;
因此,考虑到这很容易出错,我倾向于认为里德(在他的评论中)可能是对的,这对于一个班级来说更有意义。
假设我有一个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;
}
}
现在,显然这是一个微不足道的例子,因为Math.Sqrt
在这种情况下几乎可以肯定认为这种方法值得考虑。这只是用于说明目的的示例。
但我的想法是,这实现了我的三个目标,而最明显的替代方法却无法实现。具体来说:
- 我可以在类型的构造函数中执行计算;但这可能会达不到上述第二个目标(快速初始化)。
- 我可以对每个属性访问执行计算;但这可能会达不到上述第三个目标(缓存计算结果以供将来访问)。
所以是的,这个想法将有效地导致内部可变的值类型。然而,就任何外部代码而言(如我所见),它看起来是不可变的,同时带来了一些性能优势(再次,我意识到上面的示例不适合使用这个想法;“性能好处”我所说的将取决于计算实际上是否足够昂贵以保证缓存)。
我是否遗漏了什么,或者这实际上是一个值得的想法?