是否有合理的方式在.Net(Compact Framework / desktop 3.5公共子集)中表达linear type的概念,以这样的方式:(a)所需的语法不会变得过于冗长,复杂的,或其他痛苦的(b)不变量可以在运行时强制执行,也可以在编译时通过代码分析进行验证(因此,一个全力以赴的维护程序员不能轻易忽略不变量)?这里的想法是避免在子系统边界处对command objects进行防御性复制。
答案 0 :(得分:1)
线性类型,基于线性逻辑理论,与唯一性类型密切相关,是分配给具有属性的类型,它们始终只有一个引用它们。这些对于描述大型不可变值(如文件,字符串等)非常有用。
不可变类型是在实例化后内部状态无法更改的类型。
“深度不可变”类型是其依赖图包含也是“深度不可变”的引用类型的类型。如果依赖引用类型本身不是“不可变的”,则该类型称为“浅不可变”。
在C#中,我们使用引用类型和值类型。引用类型的实例可以在不同的并发执行代码之间共享,而值类型是堆栈绑定(除非装箱),在共享时复制,因此是自治的,尽管不是不可变的(并且可能包含对其他引用类型的依赖性,然后是“复制共享” )。
虽然共享引用类型的能力无疑是面向对象框架的强大功能,但在企业开发领域,它也应该被视为其主要弱点之一,并且极其谨慎地使用。任何无法以原子方式执行的东西都会暴露出脆弱性,并且有机会将错误交错,从而间歇性地造成严重破坏。
在C#中,我们所能做的最好就是描述我们的意图。通过将整个内部状态标记为私有和只读,可以部分地实现不变性。不能强制执行深层不变性(也不能浅薄),因此开发人员必须坚持用心。对状态的更改是通过静态方法返回包含请求状态的类型的新实例。
public sealed class PersonImmutable {
private readonly int _age;
private readonly string _name;
public PersonImmutable(int age, string name) {
this._age = age;
this._name = name;
}
public int Age {
get { return this._age; }
}
public string Name {
get { return this._name; }
}
public static PersonImmutable NotifyBirthday(PersonImmutable source) {
return new PersonImmutable(1 + source.Age, source.Name);
}
}
答案 1 :(得分:0)
提供的链接确实定义了LinearVariable,其定义类似于:
Option Explicit On
Option Strict On
Option Infer On
<System.Diagnostics.DebuggerDisplay("{_state}: {_value}")> _
Class LinearVariable(Of T)
Private Enum State
Unassigned
Assigned
Used
End Enum
Private _state As State = State.Unassigned
Private _value As T
Public Sub New()
'Allow creation and later assignment
End Sub
Public Sub New(ByVal Value As T)
_value = Value
_state = State.Assigned
End Sub
Public Shared Widening Operator CType(Value As T) As LinearVariable(Of T)
Return New LinearVariable(Of T)(Value)
End Operator
Public Shared Widening Operator CType(Value As LinearVariable(Of T)) As T
Return Value.Value
End Operator
Public Property Value As T
Get
If _state = State.Assigned Then
_state = State.Used
#If DEBUG Then
Return _value
#Else ' Release - free the reference immedately after use
value = _value
_value = Nothing
#End If
End If
If _state = State.Unassigned Then _
Throw New NullReferenceException("LinearVariable is unassigned")
If _state = State.Used Then _
Throw New AccessViolationException("LinearVariable has already been accessed")
Throw New InvalidOperationException
End Get
Set(ByVal Value As T)
' May want to check _state, although the "definition" at http://c2.com/cgi/wiki?LinearTypes seems to allow multiple writes
_value = Value
_state = State.Assigned
End Set
End Property
End Class
(已编译但未经测试。)
这显然只适用于运行时。我想不出在编译时试图强制使用.Value
的任何方法。
请注意,您可以设置LinearVariable
IDisposable
,然后在运行时捕获其值设置且未使用。
答案 2 :(得分:0)
.Net中有两种类型:引用类型和值类型。
通过将引用类型分配给另一个变量来复制引用类型时,只复制引用。
复制值类型时,将逐字节复制该类型的全部内容。
在这两种情况下,都无法阻止,修改或获取有关它的通知(与C ++的复制构造函数相反)。这意味着您无法在.Net中实现线性类型。
您可以改为使用不可变(或freezable)类型,正如其他人所建议的那样。