C# 如何强制字段/属性表示某种类型的物理量?
在某些类型的代码(例如模拟/游戏/优化)中,存储、操纵和显示对象的许多物理量/属性(位置、速度、距离、面积、体积、时间、时差)。在这些类型的代码中,所有这些量通常用浮点数表示,即c#中的双精度数 这允许您将时间添加到距离,将面积添加到体积,将时间添加到时间,将位置添加到位置 但你永远不想这么做。您只需要将时间差添加到时间,将距离添加到其他距离或位置,并将面积与距离相乘。尽管如此,还是很容易出错,特别是当其他人编写代码时C# 如何强制字段/属性表示某种类型的物理量?,c#,C#,在某些类型的代码(例如模拟/游戏/优化)中,存储、操纵和显示对象的许多物理量/属性(位置、速度、距离、面积、体积、时间、时差)。在这些类型的代码中,所有这些量通常用浮点数表示,即c#中的双精度数 这允许您将时间添加到距离,将面积添加到体积,将时间添加到时间,将位置添加到位置 但你永远不想这么做。您只需要将时间差添加到时间,将距离添加到其他距离或位置,并将面积与距离相乘。尽管如此,还是很容易出错,特别是当其他人编写代码时 有许多方法可以缓解这种危险。您可以定义表示各种物理量的自定义类,然后以编程方
有许多方法可以缓解这种危险。您可以定义表示各种物理量的自定义类,然后以编程方式禁止某些类型的交互。或者您遵守严格的命名约定(例如延迟时差)。在什么情况下(如果有的话),这两个选项中哪一个是最好的?如何实现第一个选项?如何为第二个选项命名 通常使用第二个选项,但更多是为了方便。命名成为一个问题,让你清楚地知道你在处理什么,即:命名属性
区域
和卷
,但即便如此,还是有一个单位问题
您可以通过创建一整套自定义类(或不可变结构类型)来处理第一种情况,以处理每种不同的组合,这可以很好地工作,但会使代码更加麻烦。框架中的DateTime
struct就是一个很好的例子——在其核心,它基本上只是一个长整型值,但它被包装到一个struct中,以防止它被用作时间上的某个时刻
请注意,其他语言也有这样的选项—例如,F允许在语言级别处理,但C中不以任何方式支持这一点。我认为最好将它们实现为结构,而不是类,因为它们是值类型。您需要执行运算符重载,以确保针对相同类型和不同类型的其他结构可以使用适当的运算符。您可能还希望重载ToString函数以输出标量值,可能需要使用单位
您还可以创建用于创建其他结构向量的通用结构-这些结构可以是二维(x和y属性)、三维(x、y和z属性)或N维(值数组)。这些结构还可以使用适当的运算符重载来执行向量计算。如果你做得正确,这将是一种与数据交互的非常自然的方式。你所描述的两个选项都是可行的,但它们都有缺点。第一个选项会导致太多的类(然后需要定义很多关系),第二个选项很容易出错 一个更好的选择是创建一个自定义类,它既封装了一个浮点数,也封装了一个单元及其多重性的列表。例如,每秒1米可能变成{n=1,类型={length:1,time:-1}。然后,您可以强制执行,除非数字的单位相同,否则不能对其进行比较、添加或减去。乘法和除法将匹配类型的多样性相加 例如
相对“最简单”的方法是检查所需的计算,然后可能与C#进行互操作,我不知道有什么简单的方法可以只在C#中完成。只需补充:F#的单位不会导出到生成的程序集,所以使用此功能的唯一方法是将所有相关代码保留在F#中。@BrianRasmussen是的,这就是为什么我真的说“在C#中不受任何支持”-如果您完全停留在F#领域内,这是很好的,但一旦您尝试进行互操作,它就毫无用处了:(还值得指出的是,您可以使用运算符重载智能地返回相关类型。在物理库中,您可以重载运算符,例如,将位移1d除以时间返回速度1d,将位移2d除以时间返回速度2d,将位移3d除以时间返回速度3d,将速度xd除以时间返回加速度1drationXD,乘以质量返回力等。这是一种非常有用的方法,可以在某些系统中的计算中添加额外的双重检查。我同意structs的观点,并重载操作。这就允许出现类似jleahy所描述的场景,其中可以将速度乘以时间跨度,得到距离这最大的好处是编译时类型检查。
1 m/s * 4 seconds = 4 meters
{n=1, types={length:1, time:-1}} * {n=4, types={time:1}} = {n=4, types={length:1,time:0}}