创建既不是真或假的bool值

时间:2018-01-19 15:11:06

标签: c#

免责声明:这与Nullable<bool>或其他内容无关。

我看到有人创建的bool值既不是true也不是false。这是为什么在C#中无法进行详尽匹配的一个例子。不幸的是,我丢失了一个示例的源代码,我真的想恢复它。

所以问题是:如何在以下代码中调用default arm?

bool b = GetMyWeirdBool()
switch (b)
{
   case true: Console.WriteLine("true"); break;
   case false: Console.WriteLine("false"); break;
   default: Console.WriteLine("neither o_0"); break;
}
IIRC通过MarshalStructLayout或其他方式进行了一些肮脏的黑客行为。

3 个答案:

答案 0 :(得分:5)

可能是值为43或类似的真实。关键是:Boolean是谎言 - 它不存在于IL级别。它只是一个整数,其值为零或非零。这适用于&#34; brtrue&#34;并且&#34; brfalse&#34;任何布尔值(1,-1或42)的操作码 - 当你在两个意味着布尔值的值之间进行相等性测试时会出现问题:a&#34; ceq&#34;对于两个实际上不相等的真正的布尔值,操作码将失败。同样,一个&#34;开关&#34;操作码(跳转表 - 在C#中常用于switch)如果值不是编译器所期望的那样将失败。

这可能会混淆某些API,在相等时将false返回到另一个真值,但在通过brtrue进行比较时报告为true。

通过unsafe代码将int视为bool

static unsafe bool GetMyWeirdBool()
{
    int i = 42;
    return *(bool*)(&i);
}

通过IL:

static bool GetMyWeirdBool()
{
    var method = new DynamicMethod("evil", typeof(bool), null);
    var il = method.GetILGenerator();
    il.Emit(OpCodes.Ldc_I4, 42);
    il.Emit(OpCodes.Ret);
    var func = (Func<bool>)method.CreateDelegate(typeof(Func<bool>));
    return func();
}

通过具有重叠字段的struct

[StructLayout(LayoutKind.Explicit)]
struct Evil
{
    public Evil(int value)
    {
        Boolean = false;
        Int32 = value;
    }
    [FieldOffset(0)]
    public bool Boolean;

    [FieldOffset(0)]
    public int Int32;

}
static bool GetMyWeirdBool()
{
    var val = new Evil(42);
    return val.Boolean;
}

答案 1 :(得分:2)

您可以使用具有显式布局的结构:

[StructLayout(LayoutKind.Explicit)]
public struct NotBool
{
    [FieldOffset(0)]
    public readonly bool Value;
    [FieldOffset(0)]
    private readonly int Int;

    public NotBool(int intValue)
    {
        Value = false;
        Int = intValue;
    }
}

测试:

NotBool notBool = new NotBool(255);
switch (notBool.Value)
{
    case true:
        break;
    case false:
        break;
    default:
        Debug.WriteLine("Default");
        break;
}

答案 2 :(得分:2)

这似乎对我有用。你得到的都不是。

unsafe
{
    for (int i = 0; i < byte.MaxValue; i++)
    {
        byte val = (byte)i;
        bool b = *(bool*)&val;

        switch (b)
        {
            case true: Console.WriteLine("true"); break;
            case false: Console.WriteLine("false"); break;
            default: Console.WriteLine("neither o_0"); break;
        }
    }
}

但请注意,这些布尔人在评论时会评估。至少对我来说,0以外的任何东西都是真的。

甚至像b == true 这样的比较结果证明是编译器优化。 b == x其中x为真且b为任何值且未评估为真的protected $casts = [ 'column_name' => 'array' ];