有没有办法使用扩展方法来实现C#中以下的实现?

huangapple go评论128阅读模式
英文:

Is there way to use extension methods to achieve below implementation in C#?

问题

我有一个方法,类似于下面的示例:

// 检查位6、7、8是否为零
if ((num >> 5) != 0)
{
    // 执行某些操作
    return false;
}

// 检查位2、3、4是否为零
if ((num & 0x0E) != 0)
{
     // 执行某些操作
     return false;
}

// 检查第1位是否为1
if ((num & 1) != 1)
{
    // 执行某些操作
    return false;
}

现在我想添加扩展方法,类似于:

num
.arebitsset((6,7,8), (如果为false则执行某些操作并从方法返回,如果为true则允许链接))
.arebitsset(2,3,4, <同上>)
.......

虽然我知道位设置检查的逻辑,但我需要知道如何根据true/false结果从方法返回或允许链接。是否可以使用func来实现?我不太确定。

注意:我有80个这样的条件需要测试,所以编写80个if条件是否合适,显然不是,所以我需要一种更紧凑的形式。

英文:

I have a method which does something like shown below :

// check if bits 6,7,8 are zero
if ((num &gt;&gt; 5) != 0)
{
    //do some thing
    return false;
}
        
// check if bits 2 ,3,4 are zero
if ((num &amp; 0x0E) != 0)
{
     //do something
     return false;
}

// check if bit 1 is 1
if ((num &amp; 1) != 1)
{
    //dosomething
    return false;
 }

and now I want to add extension method like :

   num
   .arebitsset((6,7,8) ,(do some action and return from method if false , if true allow chaining))
   .arebitsset(2,3,4) , &lt;same as above&gt;)
   .......

While I know the logic for bitset checking, but I need to know how to return from the method or allow chaining based on true/false outcome.

Is it possible by using func? I am not sure.

NOTE : I have 80 such conditions to be tested below , so is it good to write 80 if conditions , certainly not , so i need some compact form

答案1

得分: 6

Here's the translation:

你可以编写如下的扩展方法:

public static class BitSetExtensions
{
    private static bool AreBitsSet(int i, int[] bits)
    {
        // 你已经有这部分代码了
    }

    public static (int value, bool valid) CallActionIfBitsSet(this int value, int[] bits, Action action)
    {
        return CallActionIfBitsSet((value, true), bits, action);
    }

    public static (int value, bool valid) CallActionIfBitsSet(this (int value, bool valid) data, int[] bits, Action action)
    {
        if (data.valid)
        {
            data.valid = AreBitsSet(data.value, bits);

            if (data.valid) action();
        }

        return data;
    }
}

然后你可以像这样链接它们:

int num = 5;

num.CallActionIfBitsSet(new[] {1, 3, 5}, () =>
    {
        /* 动作 */
    })
    .CallActionIfBitsSet(new[] {2, 3, 4}, () =>
    {
        /* 其他动作 */
    })
    .CallActionIfBitsSet(new[] {2, 3, 6}, () =>
    {
        /* 其他动作 */
    });

个人而言,我不太喜欢这种方式,因为我认为与传统的 if 相比,接口并没有变得更简单,但这确实可行。

英文:

You could write extension methods like this:

public static class BitSetExtensions
{
    private static bool AreBitsSet(int i, int[] bits)
    {
        // you already have this
    }

    public static (int value, bool valid) CallActionIfBitsSet(this int value, int[] bits, Action action)
    {
        return CallActionIfBitsSet((value, true), bits, action);
    }

    public static (int value, bool valid) CallActionIfBitsSet(this (int value, bool valid) data, int[] bits, Action action)
    {
        if (data.valid)
        {
            data.valid = AreBitsSet(data.value, bits);

            if (data.valid) action();
        }

        return data;
    }
}

Then you can chain them like this:

int num = 5;

num.CallActionIfBitsSet(new[] {1, 3, 5}, () =&gt;
    {
        /* action */
    })
    .CallActionIfBitsSet(new[] {2, 3, 4}, () =&gt;
    {
        /* other action */
    })
    .CallActionIfBitsSet(new[] {2, 3, 6}, () =&gt;
    {
        /* other action */
    });

I am not a big fan personally because I don't think your interface gets easier this way compared to traditional if, but it would work.

答案2

得分: 0

以下是您要翻译的内容:

There is one more way to achieve something that should be ok for you.

You can define structure as in code below. Using pattern matching and basing on monads, specifically on flatMap function with signature that you can see below, it is possible to create a chain of functions that would stop executing completelty transparent to the caller, based only on what happens inside those functions.

You can read more about it if you search for Rust's Option or Haskell's Maybe. Those types (sum types) that those languages use are not however native to C#, they need some effort to implement.

For example in code below only
> 1 2 2 I got None!

Will be displayed to console as third call to FlatMap breaks the chain returning None.

This can be used to your particular problem, however it can be also used to a lot of other problems.

By inspecting type of final value you can learn if the chain of calls was succesfull.

The pro of this approach is that all ifs are completely transparent to the caller.

class Program
{
static void Main()
{
var a = new Option<int>.Some(1);
var result = a.FlatMap<int>(i => { Console.WriteLine(i); return new Option<int>.Some(i + 1); })
.FlatMap<int>(i => { Console.WriteLine(i); return new Option<int>.Some(i); })
.FlatMap<int>(i => { Console.WriteLine(i); return new Option<int>.None(); })
.FlatMap<int>(i => { Console.WriteLine(i); return new Option<int>.Some(i); });

    switch (result)
    {
        case Option&lt;int&gt;.Some some:
            Console.WriteLine("I got Some!");
            break;
        case Option&lt;int&gt;.None none:
            Console.WriteLine("I got None!");
            break;
        default:
            throw new InvalidOperationException();
    }

}

}

public abstract class Option<T>
{
public class Some : Option<T>
{
public Some(T data)
{
Data = data;
}

    public T Data;
}

public class None : Option&lt;T&gt; { }

public Option&lt;T&gt; FlatMap&lt;T&gt;(Func&lt;T, Option&lt;T&gt;&gt; action)
{
    switch (this)
    {
        case Option&lt;T&gt;.Some some:
            return action(some.Data);
        case Option&lt;T&gt;.None none:
            return none;
        default:
            throw new InvalidOperationException();
    }
}

}

英文:

There is one more way to achieve something that should be ok for you.

You can define structure as in code below. Using pattern matching and basing on monads, specifically on flatMap function with signature that you can see below, it is possible to create a chain of functions that would stop executing completelty transparent to the caller, based only on what happens inside those functions.

You can read more about it if you search for Rust's Option or Haskell's Maybe. Those types (sum types) that those languages use are not however native to C#, they need some effort to implement.

For example in code below only
> 1 2 2 I got None!

Will be displayed to console as third call to FlatMap breaks the chain returning None.

This can be used to your particular problem, however it can be also used to a lot of other problems.

By inspecting type of final value you can learn if the chain of calls was succesfull.

The pro of this approach is that all ifs are completely transparent to the caller.

class Program
{
    static void Main()
    {
        var a = new Option&lt;int&gt;.Some(1);
        var result = a.FlatMap&lt;int&gt;(i =&gt; { Console.WriteLine(i); return new Option&lt;int&gt;.Some(i + 1); })
         .FlatMap&lt;int&gt;(i =&gt; { Console.WriteLine(i); return new Option&lt;int&gt;.Some(i); })
         .FlatMap&lt;int&gt;(i =&gt; { Console.WriteLine(i); return new Option&lt;int&gt;.None(); })
         .FlatMap&lt;int&gt;(i =&gt; { Console.WriteLine(i); return new Option&lt;int&gt;.Some(i); });

        switch (result)
        {
            case Option&lt;int&gt;.Some some:
                Console.WriteLine(&quot;I got Some!&quot;);
                break;
            case Option&lt;int&gt;.None none:
                Console.WriteLine(&quot;I got None!&quot;);
                break;
            default:
                throw new InvalidOperationException();
        }

    }
}

public abstract class Option&lt;T&gt;
{
    public class Some : Option&lt;T&gt;
    {
        public Some(T data)
        {
            Data = data;
        }

        public T Data;
    }

    public class None : Option&lt;T&gt; { }

    public Option&lt;T&gt; FlatMap&lt;T&gt;(Func&lt;T, Option&lt;T&gt;&gt; action)
    {
        switch (this)
        {
            case Option&lt;T&gt;.Some some:
                return action(some.Data);
            case Option&lt;T&gt;.None none:
                return none;
            default:
                throw new InvalidOperationException();
        }
    }
}

答案3

得分: 0

你不能从方法链的中间返回。你可以发明一种模仿这种行为的方式,但这不太好,因为单独查看方法调用的人可能不会怀疑到这种行为。

既然你也在评论中要求这样做,如果你想避免使用扩展方法的话,另一种方法是创建一个测试和操作的测试对列表,如果测试成功,则在foreach循环中测试每个测试。

我不认为这会提高可读性,但你的代码中只会有一个“if”。

使用一个简单的类,像这样的类(或者可以使用ValueTupple来摆脱这个类):

public class Test
{
    public Func<int, bool> Condition { get; set; }
    public Action<int> Operation { get; set; }
}

然后你可以这样做:

var Tests = new List<Test>
{
    new Test
    {
        Condition = num => (num >> 5) != 0,
        Operation = num => { // 进行操作 }
    },
    new Test
    {
        Condition = num => (num & 0x0E) != 0,
        Operation = num => { // 进行其他操作 }
    }
    // 在这里添加所有你的80+个测试
};

// 然后只使用一个if:
foreach (var test in Tests)
{
    if(test.Condition(Number))
    {
        test.Operation(Number);
        // 无论哪个测试成功了,在返回之前,在这里执行需要执行的操作(如果需要的话)。
        return false;
    }
}
英文:

You cannot return from the middle of a method chain.
You could invent a way to mimick such a behaviour but it would be not so nice, as one reading the method call alone would not suspect such a behaviour.

Since you also asked for this in comment, an alternative method if you want to avoid the 80 "if"s not using extension methods would be to have a list of pair of test and action to perform if the test is successful, test each in a foreach loop.
I don't think you would gain any readability, but there would be only one "if" in your code.

Using a simple class like this one (alternatively, ValueTupple could be used to get rid of this class):

public class Test
{
	public Func&lt;int, bool&gt; Condition { get; set; }
	public Func&lt;int, bool&gt; Operation { get; set; }
}

You could do:

	var Tests = new List&lt;Test&gt;
	{
		new Test
		{
			Condition = num =&gt; (num &gt;&gt; 5) != 0,
			Operation = num =&gt; { // Do stuff}
		},
		new Test
		{
			Condition = num =&gt; (num &amp; 0x0E) != 0,
			Operation = num =&gt; { // Do other stuff}
		}
        // Add all your 80+ tests here
	};

// Then use a single if:
foreach (var test in Tests)
{
	if(test.Condition(Number))
	{
		test.Operation(Number);
        // Whatever the test that succeeded was, do here what you need to perform before returning, if needed.
		return false;
	}
}

答案4

得分: 0

以下是您要翻译的内容:

"Without throwing big words like monads around, you can construct an object representing the entire execution plan and then short-circuit it from the inside. It'd be very akin to making your own LINQ method, only instead of enumerating the source and then yielding the results, we need to be able to run the plan or extend it (continue) with another action. Our IExecutable&lt;T&gt; will represent a chain of actions dependent on a parameter of type T that can be executed, returning a status that allows other methods in the chain to modify the control flow as needed. We'll need a unary parameter and parameterless version:

public enum ExecutionResult
{
    RunToCompletion,
    Aborted
}

public interface IExecutable
{
    ExecutionResult Execute();
}

public interface IExecutable&lt;T&gt;
{
    ExecutionResult Execute(T argument);
}

We'll make two (technically three) implementations. First, a SimpleExecutable and SimpleExecutable&lt;T&gt;, that won't do any fancy stuff, just wrap an action and run it.

internal class SimpleExecutable : IExecutable
{
    private readonly Func&lt;ExecutionResult&gt; _action;

    public SimpleExecutable(Func&lt;ExecutionResult&gt; action) =&gt; _action = action;

    public ExecutionResult Execute() =&gt; _action();
}

internal class SimpleExecutable&lt;T&gt; : IExecutable&lt;T&gt;
{
    private readonly Func&lt;T, ExecutionResult&gt; _action;

    public SimpleExecutable(Func&lt;T, ExecutionResult&gt; action) =&gt; _action = action;

    public ExecutionResult Execute(T argument) =&gt; _action(argument);
}

Nothing interesting here, now the one you actually want, a ShortCircuitingConditionalExecutable&lt;T&gt;:

internal class ShortCircuitingConditionalExecutable&lt;T&gt; : IExecutable&lt;T&gt;
{
    private readonly Func&lt;T, ExecutionResult&gt; _action;
    private readonly Func&lt;T, bool&gt; _predicate;

    public ShortCircuitingConditionalExecutable(
        Func&lt;T, ExecutionResult&gt; action,
        Func&lt;T, bool&gt; predicate) =&gt;
        (_action, _predicate) = (action, predicate);

    public ExecutionResult Execute(T argument)
    {
        if (!_predicate(argument))
        {
            return ExecutionResult.Aborted;
        }

        _action(argument);
        return ExecutionResult.RunToCompletion;
    }
}

Execute checks the predicate, runs the method if it's true and returns a result signalling whether we should short-circuit the operation.

To make this more handy to use, let's make a few helper extensions:

public static class Executable
{
    public static IExecutable&lt;T&gt; StartWithIf&lt;T&gt;(
        Action&lt;T&gt; action,
        Func&lt;T, bool&gt; predicate) =&gt;
        new ShortCircuitingConditionalExecutable&lt;T&gt;(ReturnCompletion(action), predicate);

    public static IExecutable ContinueWith(this IExecutable source, IExecutable executable) =&gt;
        new SimpleExecutable(ChainIfCompleted(source.Execute, executable.Execute));

    public static IExecutable&lt;T&gt; ContinueWith&lt;T&gt;(this IExecutable&lt;T&gt; source, IExecutable&lt;T&gt; executable) =&gt;
        new SimpleExecutable&lt;T&gt;(ChainIfCompleted&lt;T&gt;(source.Execute, executable.Execute));

    public static IExecutable&lt;T&gt; ContinueWithIf&lt;T&gt;(
        this IExecutable&lt;T&gt; source,
        Action&lt;T&gt; action,
        Func&lt;T, bool&gt; predicate) =&gt;
        source.ContinueWith(new ShortCircuitingConditionalExecutable&lt;T&gt;(ReturnCompletion(action), predicate));

    public static IExecutable BindArgument&lt;T&gt;(this IExecutable&lt;T&gt; source, T argument) =&gt;
        new SimpleExecutable(() =&gt; source.Execute(argument));

    private static Func&lt;ExecutionResult&gt; ChainIfCompleted(
        Func&lt;ExecutionResult&gt; action1,
        Func&lt;ExecutionResult&gt; action2) =&gt;
        () =&gt;
        {
            var result = action1();
            return result != ExecutionResult.RunToCompletion ? result : action2();
        };

    private static Func&lt;T, ExecutionResult&gt; ChainIfCompleted&lt;T&gt;(
        Func&lt;T, ExecutionResult&gt; action1,
        Func&lt;T, ExecutionResult&gt; action2) =&gt;
        t =&gt;
        {
            var result = action1(t);
            return result != ExecutionResult.RunToCompletion ? result : action2(t);
        };

    private static Func&lt;T, ExecutionResult&gt; ReturnCompletion&lt;T&gt;(Action&lt;T&gt; action) =&gt;
        t =&gt;
        {
            action(t);
            return ExecutionResult.RunToCompletion;
        };
}

I've omitted a few obvious extensions we could make, but that's rather a lot of code, so maybe a motivating example of this thing in action:

class Program
{
    private static Func&lt;int, bool&gt; AreBitsSet(params int[] bits) =&gt; 
       n =&gt; bits.All(b =&gt; (n &amp; (1 &lt;&lt; b)) != 0);

    private static void Print(int n) =&gt; Console.WriteLine(n);

    static void Main(string[] args)
    {
        var num1 = (1 &lt;&lt; 2) | (1 &lt;&lt; 4) | (1 &lt;&lt; 5);
        var num2 = num1 | (1 &lt;&lt; 7);

        var executable = Executable.StartWithIf(Print, AreBitsSet(2))
            .ContinueWithIf(Print, AreBitsSet(2, 4, 5))
            .ContinueWithIf(Print, AreBitsSet(7));

        var executableNum1 = executable.BindArgument(num1);
        var executableNum2 = executable.BindArgument(num2);

        var program = executableNum1.ContinueWith(executableNum2);

        executable.Execute(num1);
        executable.Execute(num2);
        program.Execute();
    }
}

The first execution prints 52 twice (num1). The second execution prints 180 thrice (num2). The execution of program prints only 52 twice and short-circuits the rest of the execution.

This is not a fully production-ready module, as I've ignored argument validation and there are probably possible optimisations that would avoid some allocations when constructing the execution flow (we're making a lot of delegates). Also, it would be really nice to make this thing more fluent by enabling execution.ContinueWith(action).If(predicate) syntax. It's also terribly overcomplicated, since your use case requires only a very specific execution chain, but what the heck, it was fun writing it up.

Aside: To anyone interested, this is not a monad, but very close so. We would have to replace `

英文:

Without throwing big words like monads around, you can construct an object representing the entire execution plan and then short-circuit it from the inside. It'd be very akin to making your own LINQ method, only instead of enumerating the source and then yielding the results, we need to be able to run the plan or extend it (continue) with another action. Our IExecutable&lt;T&gt; will represent a chain of actions dependent on a parameter of type T that can be executed, returning a status that allows other methods in the chain to modify the control flow as needed. We'll need a unary parameter and parameterless version:

public enum ExecutionResult
{
    RunToCompletion,
    Aborted
}

public interface IExecutable
{
    ExecutionResult Execute();
}

public interface IExecutable&lt;T&gt;
{
    ExecutionResult Execute(T argument);
}

We'll make two (technically three) implementations. First, a SimpleExecutable and SimpleExecutable&lt;T&gt;, that won't do any fancy stuff, just wrap an action and run it.

internal class SimpleExecutable : IExecutable
{
    private readonly Func&lt;ExecutionResult&gt; _action;

    public SimpleExecutable(Func&lt;ExecutionResult&gt; action) =&gt; _action = action;

    public ExecutionResult Execute() =&gt; _action();
}

internal class SimpleExecutable&lt;T&gt; : IExecutable&lt;T&gt;
{
    private readonly Func&lt;T, ExecutionResult&gt; _action;

    public SimpleExecutable(Func&lt;T, ExecutionResult&gt; action) =&gt; _action = action;

    public ExecutionResult Execute(T argument) =&gt; _action(argument);
}

Nothing interesting here, now the one you actually want, a ShortCircuitingConditionalExecutable&lt;T&gt;:

internal class ShortCircuitingConditionalExecutable&lt;T&gt; : IExecutable&lt;T&gt;
{
    private readonly Func&lt;T, ExecutionResult&gt; _action;
    private readonly Func&lt;T, bool&gt; _predicate;

    public ShortCircuitingConditionalExecutable(
        Func&lt;T, ExecutionResult&gt; action,
        Func&lt;T, bool&gt; predicate) =&gt;
        (_action, _predicate) = (action, predicate);

    public ExecutionResult Execute(T argument)
    {
        if (!_predicate(argument))
        {
            return ExecutionResult.Aborted;
        }

        _action(argument);
        return ExecutionResult.RunToCompletion;
    }
}

Execute checks the predicate, runs the method if it's true and returns a result signalling whether we should short-circuit the operation.

To make this more handy to use, let's make a few helper extensions:

public static class Executable
{
    public static IExecutable&lt;T&gt; StartWithIf&lt;T&gt;(
        Action&lt;T&gt; action,
        Func&lt;T, bool&gt; predicate) =&gt;
        new ShortCircuitingConditionalExecutable&lt;T&gt;(ReturnCompletion(action), predicate);

    public static IExecutable ContinueWith(this IExecutable source, IExecutable executable) =&gt;
        new SimpleExecutable(ChainIfCompleted(source.Execute, executable.Execute));

    public static IExecutable&lt;T&gt; ContinueWith&lt;T&gt;(this IExecutable&lt;T&gt; source, IExecutable&lt;T&gt; executable) =&gt;
        new SimpleExecutable&lt;T&gt;(ChainIfCompleted&lt;T&gt;(source.Execute, executable.Execute));

    public static IExecutable&lt;T&gt; ContinueWithIf&lt;T&gt;(
        this IExecutable&lt;T&gt; source,
        Action&lt;T&gt; action,
        Func&lt;T, bool&gt; predicate) =&gt;
        source.ContinueWith(new ShortCircuitingConditionalExecutable&lt;T&gt;(ReturnCompletion(action), predicate));

    public static IExecutable BindArgument&lt;T&gt;(this IExecutable&lt;T&gt; source, T argument) =&gt;
        new SimpleExecutable(() =&gt; source.Execute(argument));

    private static Func&lt;ExecutionResult&gt; ChainIfCompleted(
        Func&lt;ExecutionResult&gt; action1,
        Func&lt;ExecutionResult&gt; action2) =&gt;
        () =&gt;
        {
            var result = action1();
            return result != ExecutionResult.RunToCompletion ? result : action2();
        };

    private static Func&lt;T, ExecutionResult&gt; ChainIfCompleted&lt;T&gt;(
        Func&lt;T, ExecutionResult&gt; action1,
        Func&lt;T, ExecutionResult&gt; action2) =&gt;
        t =&gt;
        {
            var result = action1(t);
            return result != ExecutionResult.RunToCompletion ? result : action2(t);
        };

    private static Func&lt;T, ExecutionResult&gt; ReturnCompletion&lt;T&gt;(Action&lt;T&gt; action) =&gt;
        t =&gt;
        {
            action(t);
            return ExecutionResult.RunToCompletion;
        };
}

I've omitted a few obvious extensions we could make, but that's rather a lot of code, so maybe a motivating example of this thing in action:

class Program
{
    private static Func&lt;int, bool&gt; AreBitsSet(params int[] bits) =&gt; 
       n =&gt; bits.All(b =&gt; (n &amp; (1 &lt;&lt; b)) != 0);

    private static void Print(int n) =&gt; Console.WriteLine(n);

    static void Main(string[] args)
    {
        var num1 = (1 &lt;&lt; 2) | (1 &lt;&lt; 4) | (1 &lt;&lt; 5);
        var num2 = num1 | (1 &lt;&lt; 7);

        var executable = Executable.StartWithIf(Print, AreBitsSet(2))
            .ContinueWithIf(Print, AreBitsSet(2, 4, 5))
            .ContinueWithIf(Print, AreBitsSet(7));

        var executableNum1 = executable.BindArgument(num1);
        var executableNum2 = executable.BindArgument(num2);

        var program = executableNum1.ContinueWith(executableNum2);

        executable.Execute(num1);
        executable.Execute(num2);
        program.Execute();
    }
}

The first execution prints 52 twice (num1). The second execution prints 180 thrice (num2). The execution of program prints only 52 twice and short-circuits the rest of the execution.

This is not a fully production-ready module, as I've ignored argument validation and there are probably possible optimisations that would avoid some allocations when constructing the execution flow (we're making a lot of delegates). Also, it would be really nice to make this thing more fluent by enabling execution.ContinueWith(action).If(predicate) syntax. It's also terribly overcomplicated, since your use case requires only a very specific execution chain, but what the heck, it was fun writing it up.

Aside: To anyone interested, this is not a monad, but very close so. We would have to replace Execute with something that returns the constructed Action&lt;T&gt; delegate and then write up the appropriate bind function. Then we'd get a monad over Actions of any T, and we could still make Execute into an extension method that gets the delegate and immediately calls it. The BindArgument is a special case of a bind: t =&gt; bind(e, f =&gt; () =&gt; f(t)).

答案5

得分: 0

使用 if 语句检查条件是最有效且最容易调试的方法。在发生异常时,您将知道在哪里查找错误。我的唯一建议是通过使用单个 if 和多个 else if 来消除重复的 return false; 语句:

public static bool Execute(int num)
{
    if ((num >> 5) != 0) // 检查位 6、7、8 是否为零
    {
        // 做一些事情
    }
    else if ((num & 0x0E) != 0) // 检查位 2、3、4 是否为零
    {
        // 做一些事情
    }
    else if ((num & 1) != 1) // 检查位 1 是否为 1
    {
        // 做一些事情
    }
    else
    {
        return false; // 没有执行任何操作
    }
    return true; // 执行了一些操作
}
英文:

Checking the conditions with an if statement is the most efficient and the easiest to debug. In case of an exception you'll know where to look for the bug. My only suggestion is to get rid of the recurrent return false; statements, by using a single if with multiple else if:

public static bool Execute(int num)
{
    if ((num &gt;&gt; 5) != 0) // check if bits 6, 7, 8 are zero
    {
        // do something
    }
    else if ((num &amp; 0x0E) != 0) // check if bits 2, 3, 4 are zero
    {
        // do something
    }
    else if ((num &amp; 1) != 1) // check if bit 1 is 1
    {
        // do something
    }
    else
    {
        return false; // nothing has been done
    }
    return true; // something has been done
}

huangapple
  • 本文由 发表于 2020年1月7日 01:02:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/59616139.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定