我有两个问题,请给我们一些帮助。
我的客户端代码需要访问随时间变化的变量/值,事实上,它是在检索时计算的,并且在运行时通过多次方法检索多次,但是,它的计算并不总是如此可能因为它的要求并不总是存在,在这种情况下,会返回 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一个镜头,让它们变得有用在这种情况下(不仅在我寻找未分配的值时,我使用它们的情况)。我希望有人可以就此发表意见。
感谢。
答案 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)我看不到多少尝试只有一种方法可以做两件事。