首页 > 解决方案 > 有没有一种方法可以简化检查值是某物的倍数而不是 0 的方法?

问题描述

我有这个代码:

if (Settings.Trk3 % 20 == 0 && Settings.Trk3 > 0)
    // Do something

看起来可能有更好的编码方法,但我想不出该怎么做。有人有建议吗?

标签: c#

解决方案


如果它是您的代码库中的常见操作,我会使用扩展方法 - 但如果它是一次性检查,那么我会保留您的代码原样,因为您现有的代码清楚地表明意图并且因为大于零和模除法是不同的操作,应该分开。

也就是说 - 这是扩展方法的样子:

public static class IntegerExtensions
{
    public static Boolean IsNonZeroMultipleOf( this Int32 value, Int32 divisor)
    {
        return ( value > 0 ) && ( value % divisor ) == 0;
    }
}

用法:

if( Settings.Trk3.IsNonZeroMultipleOf( 20 ) )
{
    // Do something.
}

关于性能:JIT 应该足够聪明,可以内联琐碎的非虚拟方法调用,尤其是对于纯函数,包括扩展方法,因此如果绝对必要,在紧密循环中使用此代码是安全的。(我认为没有[Pure]必要使用该属性)。

但是,如果您想成为一个绝对糟糕的程序员,那么请使用带有隐式转换为/从Int32和重载运算符的自定义结构。此代码(滥用)>>操作员执行与IsNonZeroMultipleOf上述相同的操作。(至少通过使用>>它对用户来说更明显的是发生了一些奇怪的事情而不是重载%运算符):

public struct MyInteger
{
    private readonly Int32 value;

    public MyInteger( Int32 value )
    {
        this.value = value;
    }

    public static implicit operator Int32( MyInteger mi ) => mi.value;
    public static implicit operator MyInteger( Int32 value ) => new MyInteger( value );

    public static Boolean operator >>(MyInteger value, Int32 divisor)
    {
        return ( value.value > 0 ) && ( value.value % divisor ) == 0;
    }
}

用法:

// Note that `Settings.Trk3` is still an `Int32`. The assignment to `MyInteger` works because of the `implicit operator` feature.

MyInteger mi = Settings.Trk3;
if( mi >> 20 )
{
    // Do something.
}

因为此代码使用值类型的结构,仅进行非虚拟调用并且没有堆分配(new用于 C# 中结构的堆栈分配,而不仅仅是 GC 堆)此代码也应该很好用在零影响的性能关键代码中。


推荐阅读