检查有效/存在的值时,Nullable与Out参数

时间:2017-09-22 02:49:42

标签: c# unity3d c#-4.0 nullable out

我有两个问题,请给我们一些帮助。

我的客户端代码需要访问随时间变化的变量/值,事实上,它是在检索时计算的,并且在运行时通过多次方法检索多次,但是,它的计算并不总是如此可能因为它的要求并不总是存在,在这种情况下,会返回 false null ,客户端会对此进行检查以决定是否继续。现在,我有两种方法,第一种, A ,是我的经典之作, B 然而,对我来说也很好。

A)我有一个out参数,类似于某些C#库中的TryParse方法:

public bool GetLeadingTrailSegment(out Vector3 lastTrailSegment)
{
    if (_line.positionCount > 1)
    {
        lastTrailSegment = lead - _line.GetPosition(_line.positionCount - 2);
        return true;
    }
    lastTrailSegment = Vector3.zero;
    return false;
}

B)我有这个可以为空的属性,它尝试执行与上面代码相​​同的工作:

public Vector3? leadingTrailSegment
{
    get
    {
        if (_line.positionCount > 1)
        {
            return lead - _line.GetPosition(_line.positionCount - 2);
        }
        return null;
    }
}

客户端代码如下:

A)这里bool告诉客户端代码值是否安全(有用?)使用。

public bool IsDrawingOverAllowed(LayoutPointer pointer)
{
    Vector3 leadingTrailSegment;
    if (pointer.GetLeadingTrailSegment(out leadingTrailSegment))
    {
        return !midline.ParallelTo(leadingTrailSegment);
    }
    return true;
}

B)这里,nullable的HasValue属性为false的事实告诉客户端它是否安全:

public bool IsDrawingOverAllowed(LayoutPointer pointer)
{
    Vector3? leadingTrailSegment = pointer.leadingTrailSegment;
    if (leadingTrailSegment.HasValue)
    {
        return !midline.ParallelTo(leadingTrailSegment.Value);
    }
    return true;
}

第一个问题:在这两种方法中,哪种方法最好或者它们之间的利弊是什么?

第二个问题:我曾经将客户 B 方法写成:

public bool IsDrawingOverAllowed(LayoutPointer pointer)
{
    if (pointer.leadingTrailSegment.HasValue)
    {
        return !midline.ParallelTo(pointer.leadingTrailSegment.Value);
    }
    return true;
}

这是错的,对吧?因为nullable的Value属性可能已被第二次调用更改。

我最喜欢out参数方法,你可以在if子句中使用结果,并且变量甚至可以在其他版本的C#中内联声明,但是我真的想要给nullables一个镜头,让它们变得有用在这种情况下(不仅在我寻找未分配的值时,我使用它们的情况)。我希望有人可以就此发表意见。

感谢。

2 个答案:

答案 0 :(得分:4)

我更喜欢一个返回null的调用,而不是使用输出参数。输出参数是一种副作用"易受代码构造,我个人真的不喜欢。这意味着调用代码必须在使用之前定义一个变量,并且它会引入一些弱点,如果你在意外地输入错误的变量,很容易引发错误。它还会阻止您使用带有null-conditional和null-coalescing运算符的调用链中的代码。你不能做var v = GetLeadingTrailSegment() ?? new Vector3();

之类的事情

第二个兴趣点是使用Nullable。如果Vector3类型是值类型,那么这很好并且有意义。如果它是一个引用类型(几乎除了.NET中的整数类型和结构之外的所有内容),则不需要它。只需return null;if (variable != null) { ... }。返回bool的情况通常是在返回值发生冲突时。例如,如果null本身作为有效值返回,则需要一种方法来区分有效的null或无效的响应。这似乎不是这种情况。

答案 1 :(得分:0)

我的两分钱:)

tldr:

我宁愿问为什么你想要一个返回布尔值的方法,但这个名字提示另一个东西。

<小时/> 如果我有player.GetCurrentHp()并且如果玩家没有hp或者hp == 0,则该方法返回false,我认为该名称具有误导性,我宁愿使用player.isAlive()方法。

从逻辑或软件的角度来看,本身并没有什么不妥,但我不会帮助下一个开发人员使用该代码,或者在6个月内完成自己的工作。

在你的情况下,我将使用LayoutPointer的两种方法;

public bool IsValid() // <--- I like when boolean methods represent 'is, can, have' actions, ideas, or properties. 
{
    return _line.positionCount > 1;
} 

public bool GetLeadingTrailSegment()
{
    if (!IsValid()) 
    {
        return Vector3.zero;
    }

    return (lead - _line.GetPosition(_line.positionCount - 2));
}

然后;

public bool IsDrawingOverAllowed(LayoutPointer pointer)
{
    if (pointer == null) 
    {
        Debug.LogWarning("IsDrawingOverAllowed: Pointer is null!");
        return true; // or false, it depends on your design..
    }

    if (!pointer.IsValid()) // <-- I also like early returns :D 
    {
        return true;
    }

    var leadingTrailSegment = pointer.GetLeadingTrailSegment()
    return !midline.IsParallelTo(leadingTrailSegment);
}

我知道可以更加冗长&#39;但请记住,为机器创建代码很容易,但人类的代码更难。最后,您希望有一些易于阅读,理解和维护的代码。

旁注;是的,我知道有时候会有用,比如在Physics.Raycast,但是如果你没有实现TryParse pattern(如果你想要避免使用try / catch)我看不到多少尝试只有一种方法可以做两件事。