C# 表示数学未知数的可为null的类成员

C# 表示数学未知数的可为null的类成员,c#,nullable,C#,Nullable,假设我有一个类点: class Point { public double? x, y; } 为了表明x或y是未知的,我将它们的类型设置为null 现在,当在数学表达式中使用这些值时,很不方便每次都将它们的值转换为两倍。例如,Math.Sin(p.x)将产生编译时错误;您必须将其转换为:Math.Sin((double)p.x) 我解决强制转换问题的方法是使用执行强制转换的包装器只读属性: class Point { public double? x, y; publ

假设我有一个类

class Point
{
    public double? x, y;
}
为了表明
x
y
是未知的,我将它们的类型设置为null

现在,当在数学表达式中使用这些值时,很不方便每次都将它们的值转换为两倍。例如,
Math.Sin(p.x)
将产生编译时错误;您必须将其转换为:
Math.Sin((double)p.x)

我解决强制转换问题的方法是使用执行强制转换的包装器只读属性:

class Point
{
    public double? x, y;

    public double X { get { if (x != null) return (double)x; else throw new Exception(); } }
    public double Y { get { if (y != null) return (double)y; else throw new Exception(); } }
}

这是一个好方法吗?

您可以使用
可空
属性:

Math.Sin(p.x.Value)

如果未设置该值,这将引发异常,因此相当于您的代码

关于这些方法的相对优点:


在IMO中,基于属性的方法保护消费者不受实现细节的影响,即
x
在内部存储为
Nullable
,以表示未知性。如果消费者只希望处理“已知”价值,这将是我的偏好。但是,如果消费者希望满足
x
仍然“未知”的情况,那么公开
Nullable
属性将是一个好办法(任何消费者都可以使用
Nullable
HasValue
属性进行检查).

我个人不太喜欢尝试访问属性时引发的泛型异常(尤其是在访问
时引发的
InvalidOperationException
。Value
of
null
when
HasValue==false
时)。相反,我将公开用于指定是否定义值的布尔属性:

开发商在尝试访问物业之前检查成员的有效性是合同的一部分:

public class Point
{
    private double? x;
    private double? y;

    public bool IsXDefined { get { return this.x.HasValue; } }

    public bool IsYDefined { get { return this.y.HasValue; } }

    // Returns an undefined value (default(double)) in case X is not defined
    // This is a part of the contract that X is valid if, and only if IsXDefined is true.
    public double X { get { return x ?? default(double); } }

    public double Y { get { return y ?? default(double); } }
}

Point p = new ...
if (p.IsXDefined)
{
    double zz = p.X ....
}

实际上,对于同一个目标有不同的方法,但重要的是开发人员知道代码的实际用途。异常是让开发人员知道他试图读取的属性状态不好的好方法

在上面的代码中,X属性的文档将显示“点的X坐标(如果已定义)。要确保
X
是有效值,请在尝试访问此属性之前检查
IsXDefined
是否返回true”

PointCoordinatedDefinedException
也很好:

public double X
{
    get
    {
        if (this.IsXDefined)
        {
            return this.x.Value;
        }

        throw new PointCoordinateNotDefinedException();
    }
}
合同也一样:X属性的文档会说“如果未定义坐标,则可以抛出
PointCoordinatedDefinedException
异常。在尝试访问此属性之前,请检查
IsXDefined
是否返回true”

这两种方法对我来说都没问题,也许异常更好。你是对的,因为如果值未指定,它会使应用程序崩溃(这将防止应用程序使用错误的值运行(比查看stacktrace中抛出的异常更难调试))


但是,我不认为在属性抛出异常之前尝试访问属性是个好主意。我更喜欢在访问属性之前测试
IsXDefined
布尔值。

我也不喜欢当null值没有值时抛出的
invalidoOperationException
,但是返回默认值反而会隐藏类中粗心使用者的bug。我宁愿抛出一个异常,如果
invalidoOperationException
不够具体,那么创建一个
PointCoordinatedDefinedException
或类似的东西。我猜想您考虑过这样一种方法,所以我很好奇为什么您更喜欢默认值方法。您可以只执行public double X{get{return X.HasValue?X:throw new pointCoordinationEndDefinedException();}@ken2k我完全同意您捕获异常的观点:客户端应该调用
IsXDefined
,而不是使用try-catch。我刚刚想到,定义的类不是线程安全的,因此在多线程程序中,检查仍然不能保证不会抛出异常。调用
IsXDefined
X
之间的值可以设置为null。这是引发异常的另一个(更有说服力的)原因,因为默认值方法可能会导致客户机认为
0.0
是有效值,因为他们在读取
X
之前已选中
已定义
!顺便说一句,当我发布第一条评论时,我已经对你的答案投了更高的票,所以如果你的投票总数没有增加,不要认为我是在冷落你的编辑:)
public double X
{
    get
    {
        if (this.IsXDefined)
        {
            return this.x.Value;
        }

        throw new PointCoordinateNotDefinedException();
    }
}