javascript - 如何将此 Javascript 片段转换为 C#
问题描述
Javascript:
function bounds(a, b, c) {
null != b && (a = Math.max(a, b));
null != c && (a = Math.min(a, c));
return a
}
老实说,我什至不明白这里发生了什么。如果b
不为空,则被a
设置Math.max(a, b)
。如果c
不为空,a
则从Math.min(a, c)
?
如何将其转换为 C#?
PS这是我的翻译。这个对吗?
private double bounds(double a, double? b, double? c) {
if (b != null) a = Math.Max(a, b.Value);
if (c != null) a = Math.Min(a, c.Value);
return a;
}
解决方案
老实说,我什至不明白这里发生了什么。
我也不。该代码似乎实现了合同“如果c
是最小元素,则返回它,否则,返回 、 和 的中间元素a
,b
以及c
一些未知目的的可空性检查。
这是一个奇怪的实现合同,它让我认为它可能是一个未经测试的“返回中间元素”的实现,它有一个错误;如果c
在实践中永远不是最小的元素,也许这个错误永远不会被捕获。
如何将其转换为 C#?
了解上下文中代码的含义,然后在惯用的 C# 中实现这些语义。理解是重要的部分;一旦你理解了代码,编写一个正确的、可测试的实现就很简单了。
这是我的翻译。这个对吗?
private double bounds(double a, double? b, double? c) {
if (b != null) a = Math.Max(a, b.Value);
if (c != null) a = Math.Min(a, c.Value);
return a;
}
这是正确的,因为它准确地实现了原始的、可能有错误的代码的语义。但也好不到哪里去。让我们改进它。突出三点:
- 该方法不消耗
this
,所以应该是static
。 - 该方法是 C# 方法,应遵循 C# 的命名约定。
- 覆盖其形式的方法在设计时难以阅读,在运行时也难以调试。就此而言,任何改变变量的方法都比不改变变量的方法更难理解。
- 对它们有意义的名为
a
,b
,的变量c
很难阅读,因为它们掩盖了这些含义。
让我们修复所有这些。
private static double Bounds(double a, double? b, double? c)
{
double larger = (b == null) ? a : Math.Max(a, b.Value);
double smaller = (c == null) ? larger : Math.Min(larger, c.Value);
return smaller;
}
我们仍然没有 , 和 的好名字a
,b
但c
至少我们知道larger
并smaller
反映了它们的含义。
我们完了吗?总是问自己我怎样才能让这更简单?
您可以通过将检查移动到帮助程序中来使其更简单。
private static double Max(double x, double? y) =>
(y == null) ? x : Math.Max(x, y.Value)
private static double Min(double x, double? y) =>
(y == null) ? x : Math.Min(x, y.Value)
现在我们的方法变成了:
private static double Bounds(double a, double? b, double? c)
{
double larger = Max(a, b);
double smaller = Min(larger, c);
return smaller;
}
现在我们意识到我们可以将其重写为
private static double Bounds(double a, double? b, double? c) =>
Min(Max(a, b), c);
当然还不清楚这个东西的目的是什么,但我希望你同意我的实现在它的行动中再清楚不过了。在我的实现中,很明显语义是“如果c
最少,则返回它,否则返回中间元素”。将我的版本的可理解性与原始的可怕混乱进行比较,看看哪个更容易理解。
这里的教训是什么?
- 将代码组织成单一赋值形式
- 将复杂的逻辑移到辅助方法中,将其抽象出来
- 重写代码以消除不必要的解释变量。
- 代码变得干净且易于理解。
进一步的沉思;假设我的猜想是对的,意图是这样写:
private static double Middle(double test, double? bottom, double? top)
该方法的语义是:
bottom
并且top
可能都为空。- 如果两者都不为空,则
bottom
必须是较小的。 - 如果
bottom
和top
都不为空,则返回中间的值。 - 如果
bottom
和top
都为空,那么test
就是中间的值。 - 如果
bottom
为null但top
不为null,则和中较小test
的top
值是中间的值。在这里,我们将“null”视为底部的“负无穷大”。 - 类似地,如果
top
为空但bottom
不是,则 和 中的较大者bottom
是test
中间的。在这里,空顶部被视为“正无穷大”。
这实际上是一个非常明智的合约,但它要求我们知道它bottom
总是比top
它们不都为空时要小。C# 中的一个好的实现要么是Debug.Assert
这个事实(如果方法是private
),要么throw
是违反了先决条件(如果方法是public
)。
如果是这种情况,那么更好的选择是这样做:
private static double Middle(double test, double? bottom, double? top) =>
Middle(
test,
bottom ?? Double.NegativeInfinity,
top ?? Double.PositiveInfinity);
private static double Middle(double test, double bottom, double top) =>
Math.Min(Math.Max(test, bottom), top);
(如果您不熟悉??
,则读作“coalesce”,x??y
意思是“如果x
不为空则使用x.Value
,否则使用y
”。这是一个非常有用的运算符。)
再一次,看看当你在编写代码时考虑到可读性时代码看起来多么漂亮和简单。很明显,“null 表示底部为负无穷大,顶部为正无穷大”,因为这就是代码所说的!
或者,编写一个正确的 Middle 实现,不需要对三个输入进行任何排序:
// True if test is between b1 and b2, false otherwise
private static bool Between(double test, double b1, double b2) =>
((b1 <= test) & (test <= b2)) | ((b2 <= test) & (test <= b1));
// Returns the middle value of a, b, and c.
private static double Middle(double a, double b, double c)
{
if (Between(a, b, c) return a;
if (Between(b, a, c) return b;
return c;
}
或者,如果你喜欢
private static double Middle(double a, double b, double c) =>
Between(a, b, c) ? a : Between(b, a, c) ? b : c;
现在我们可以再次轻松地编写我们的 Bounds 方法:
private static double Bounds(double test, double? bottom, double? top) =>
Middle(
test,
bottom ?? Double.NegativeInfinity,
top ?? Double.PositiveInfinity);
再一次,想想我们在这里努力的目标。做一件事并且做得非常好的简单方法。一旦你有了这些,你就可以使用这些方法来构建其他简单的方法,并逐渐增加程序的复杂性,而不会使其难以理解。
推荐阅读
- google-apps-script - Google Sheets Script - 这个复制列的脚本有效,但它的形式不好?
- xamarin.forms - 如何创建约会的调度程序/看板视图
- python - python中的内部函数没有在正确的位置返回
- python - 我得到一个索引类型不合适的 IndexError,但我已经使用 int() 函数对索引进行了类型转换。有人可以帮忙解释一下吗?
- c# - Web API - 此模型项字典需要类型 'System.Collections.Generic.IEnumerable
- deep-learning - yolov3上采样层使用的上采样技术是什么?互联网上没有资源,原始论文没有很好地描述它
- python-3.x - 为什么python3 str有startswith而不是starts_with?
- reactjs - 如何获取 Firebase 存储数据
- angular - Angular - 无法从 ngForm 获取 .ts 文件中的电子邮件值
- php - 如何在一个 HTML 表格中显示多个数组变量?