可以在C#中缩短数学参考吗?

Ben*_*Ben 7 c# syntax import using

在VB.NET中,我可以通过导入System.Math并直接引用其方法来使我的数学代码更加清晰:

Imports System.Math
[...]
Return New Vector3(Sin(az) * Cos(el), Cos(az) * Cos(el), Sin(el))
Run Code Online (Sandbox Code Playgroud)

但我不认为C#可以使用类来隐式访问它们的方法,所以我必须做类似的事情:

using System;
[...]
return new Vector3(Math.Sin(az) * Math.Cos(el), Math.Cos(az) * Math.Cos(el), Math.Sin(el));
Run Code Online (Sandbox Code Playgroud)

但那很难看; 它需要自己的滚动条!有没有办法用C#写一些看起来像我的VB.NET代码的东西?我可以为Sin和Cos编写局部包装器方法,但不会降低性能(因为函数调用的开销)?而且,这需要为我正在使用的每个类中使用的每个Math函数编写包装函数; 这也不是那么令人满意.

jco*_*and 12

您可以System.Math使用using指令给出别名:

using M = System.Math;

return new Vector3(M.Sin(az) * M.Cos(el), M.Cos(az) * M.Cos(el), M.Sin(el));
Run Code Online (Sandbox Code Playgroud)

这是我得到的最好的.

我可以为Sin和Cos编写局部包装器方法,但不会降低性能(因为函数调用的开销)?

你可以,并且在那时你可以使用泛型和其他细节使它更方便,但你仍然会引用这样的库,除非所有数学都发生在这个代码作为方法出现的同一个类中.

"从开销中获得性能"这一问题的答案是"额外的堆栈帧,这对于标准应用程序而言非常明显." 如果你处于紧张的循环中,那么是的,这将是一个问题.

  • 你打败了我 (2认同)
  • 虽然这确实回答了用户的问题,但我强烈反对使用它.这比完全写出类名要简单得多. (2认同)
  • 我和一些人合作过,但无论如何,这会有什么影响呢?它是关于代码和代码约定的.即使它是类的别名,它仍然是类名.这些在公共代码约定中都是大写的(哎呀,即使是JavaScript"构造函数"也是以大写字母写的,这是出于可读性的原因). (2认同)
  • @jcolebrand:我同意Lucero的观点.`m.Sin(...)`*看起来像它在某事上调用实例方法..NET命名约定非常明确 - 类型名称以大写字母开头.我不明白为什么这个惯例应该是因为我们对它进行别名而不在窗外. (2认同)
  • @jcolebrand,别担心我,我呼吸正常.我向Ben提出了一个建议(其他人似乎同意我的观点),因为感觉这是正确的事,因为你问我解释了原因.这就是......*耸耸肩* - 编辑:关于懒惰的部分,无论哪种方式都是一个角色,大写怎么会不那么懒惰?我只是懒惰 - 遵循惯例只是因为它减少了思考的需要(这是我的意思,使人类解析器更容易). (2认同)

vcs*_*nes 9

从C#6.0开始,您可以通过添加using static声明来缩短数学引用:

using static System.Math;
Run Code Online (Sandbox Code Playgroud)

这允许您使用该Math类型的静态成员,而不使用类型名称限定它:

public void Foo()
{
     var bar = Sin(8);
}
Run Code Online (Sandbox Code Playgroud)

由于目前根本无法在全球范围内应用使用声明,因此无法"全局"执行此操作.

对于那些不使用C#6的人

但是不会降低性能(因为函数调用的开销)?

我不担心.编写代码以使其可读.我们可以用几种不同的方式编写方法.第一个,就是添加空格:

return new Vector3(
    Math.Sin(az) * Math.Cos(el),
    Math.Cos(az) * Math.Cos(el),
    Math.Sin(el)
);
Run Code Online (Sandbox Code Playgroud)

您也可以将它放在辅助方法中.

jcolebrand的回答是一个很好的做法,但它需要在using m = System.Math;任何地方添加.


Caf*_*eek 7

你可以加

using M = System.Math;
Run Code Online (Sandbox Code Playgroud)

然后就做

return new Vector3(M.Sin(az) * M.Cos(el), M.Cos(az) * M.Cos(el), M.Sin(el));
Run Code Online (Sandbox Code Playgroud)

但是......我没有看到真正的价值

事实上,我认为应该存储每个变量,并用更好的名称来表示它们是什么.看着这个,我看不出正在做什么.

var sinAz = Math.Sin(az); //Could these be named better?  Perhaps with words in the correct domain 
var cosAz = Math.Cos(az);
var sinEl = Math.Sin(el);
var cosEl = Math.Cos(el);

return new Vector3(sinAz * cosEl, cosAz * cosEl, sinEl);
Run Code Online (Sandbox Code Playgroud)

或者更好的是,Vector3实际使用的三个参数是什么?

var parm1 = Math.Sin(Az) * Math.Cos(El);  //What should parm1, parm2, parm3 be called?
var parm2 = Math.Cos(Az) * Math.Cos(El);
var parm3 = Math.Sin(Az);

return new Vector3(parm1, parm2, parm3);
Run Code Online (Sandbox Code Playgroud)

这将极大地提高可读性,因为下一个人将更好地理解公式是什么.

  • 我意识到parm1是一个可怕的名字,但我不知道该域名是否足以给它一个合适的...因此评论. (3认同)

Jon*_*eet 7

但那很难看; 它需要自己的滚动条!

是的,在Stack Overflow上,宽度很短.你必须把它放在多行上:

return new Vector3(Math.Sin(az) * Math.Cos(el),
                   Math.Cos(az) * Math.Cos(el),
                   Math.Sin(el));
Run Code Online (Sandbox Code Playgroud)

就个人而言,我认为无论如何都更具可读性,因为现在三个不同的值更清楚地区分了.空白行是一个比逗号,IMO更清晰的分隔符.如果你有几个足够相似的参数可以让它们一起丢失,那么为了清晰起见,请使用多行.

是的,如果你可以写一些东西在某种程度上会很好Sin(az)- 但C#中没有任何东西可以让你这样做,所以我坚持重新格式化代码以便于阅读.


Luc*_*ero 5

您可以创建一个将调用包装为扩展方法的类:

public static class MathExtensions {
    public static double Sin(this double value) {
        return Math.Sin(value);
    }
    public static double Cos(this double value) {
        return Math.Cos(value);
    }
}

return new Vector3(az.Sin() * el.Cos(), az.Cos() * el.Cos(), el.Sin());
Run Code Online (Sandbox Code Playgroud)

编译器应该内联这些调用,以便性能不会真正有所不同.