我有一种方法,其操作如下所示:
// check if bits 6,7,8 are zero
if ((num >> 5) != 0)
{
//do some thing
return false;
}
// check if bits 2 ,3,4 are zero
if ((num & 0x0E) != 0)
{
//do something
return false;
}
// check if bit 1 is 1
if ((num & 1) != 1)
{
//dosomething
return false;
}
现在我想添加扩展方法,如:
num
.arebitsset((6,7,8) ,(do some action and return from method if false , if true allow chaining))
.arebitsset(2,3,4) , <same as above>)
.......
虽然我知道位集检查的逻辑,但是我需要知道如何从方法中返回或允许基于正确/错误结果进行链接。
使用func是否可能?我不确定。
注意:我有80个这样的条件要在下面进行测试,如果条件一定,最好写80个条件,当然不是,所以我需要一些紧凑的表格
答案 0 :(得分:7)
您可以编写如下扩展方法:
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;
}
}
然后您可以像这样链接它们:
int num = 5;
num.CallActionIfBitsSet(new[] {1, 3, 5}, () =>
{
/* action */
})
.CallActionIfBitsSet(new[] {2, 3, 4}, () =>
{
/* other action */
})
.CallActionIfBitsSet(new[] {2, 3, 6}, () =>
{
/* other action */
});
我个人不是一个大粉丝,因为我认为与传统的if
相比,您的界面不会更容易使用,但是它可以正常工作。
答案 1 :(得分:0)
还有另一种方法可以使您满意。
您可以按照下面的代码定义结构。使用模式匹配并基于monad,特别是基于flatMap
具有签名的函数(您可以在下面看到),可以创建一系列函数,这些函数将停止执行对调用者透明的完全调用,仅基于这些调用中发生的事情功能。
如果您搜索Rust的Option
或Haskell的Maybe
,则可以了解更多信息。这些语言使用的那些类型(求和类型)不是C#固有的,它们需要付出一些努力才能实现。
例如仅在下面的代码中
1 2 2我什么都没有!
当对FlatMap
的第三次调用中断返回None
的链时,将显示在控制台上。
这可以用于您的特定问题,但是也可以用于许多其他问题。
通过检查最终值的类型,您可以了解调用链是否成功。
此方法的优点是所有ifs
对呼叫者都是完全透明的。
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<int>.Some some:
Console.WriteLine("I got Some!");
break;
case Option<int>.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<T> { }
public Option<T> FlatMap<T>(Func<T, Option<T>> action)
{
switch (this)
{
case Option<T>.Some some:
return action(some.Data);
case Option<T>.None none:
return none;
default:
throw new InvalidOperationException();
}
}
}
答案 2 :(得分:0)
您不能从方法链的中间返回。 您可以发明一种模仿这种行为的方法,但它并不是那么好,因为仅阅读方法调用的人就不会怀疑这种行为。
由于您也曾在评论中要求这样做,因此,如果您要避免使用不使用扩展方法的80个“如果”,那么另一种方法是列出测试和操作对的列表,如果测试成功,在foreach循环中测试每个。 我认为您不会获得任何可读性,但是您的代码中只会有一个“ if”。
使用像这样的简单类(或者,可以使用ValueTupple摆脱该类):
public class Test
{
public Func<int, bool> Condition { get; set; }
public Func<int, bool> Operation { get; set; }
}
您可以这样做:
var Tests = new List<Test>
{
new Test
{
Condition = num => (num >> 5) != 0,
Operation = num => { // Do stuff}
},
new Test
{
Condition = num => (num & 0x0E) != 0,
Operation = num => { // 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;
}
}
答案 3 :(得分:0)
使用if
语句检查条件是最有效和最容易调试的。如果发生异常,您将知道在哪里寻找错误。我唯一的建议是通过使用单个return false;
和多个if
来摆脱重复的else if
语句:
public static bool Execute(int num)
{
if ((num >> 5) != 0) // check if bits 6, 7, 8 are zero
{
// do something
}
else if ((num & 0x0E) != 0) // check if bits 2, 3, 4 are zero
{
// do something
}
else if ((num & 1) != 1) // check if bit 1 is 1
{
// do something
}
else
{
return false; // nothing has been done
}
return true; // something has been done
}