【问题标题】:How to create 1 / 0 returning type for bool?如何为 bool 创建 1 / 0 返回类型?
【发布时间】:2020-03-19 23:28:02
【问题描述】:

在 C# 中,如何为 bool 创建自定义类型/转换?为了更好地解释,我想要这样的表达:

bool cond=...;
int myVar=  cond as customType;

所以,我希望 customType 表现得像 myVar 变成 01,取决于 cond(如果为真,则为 1,否则为 0)。

这可能吗?


请不要向我提供cond ? 1 : 0 解决方案或其他解决方案。我问的正是我问的问题,所以在标记之前重新阅读(或分析)它。

【问题讨论】:

  • 为什么要引入customType?为什么不只是myVar = cond ? 1 : 0
  • Convert.ToBoolean(表达式) ?
  • 您在寻找类似this 的东西吗? (带有隐式运算符的自定义类型)
  • 您可以定义转换,但 as 不会调用用户定义的转换

标签: c# casting typecasting-operator


【解决方案1】:

是的,您可以这样做。如果您想要一个行为类似于内置类型的自定义类型,则必须注意覆盖从System.Object 继承的一些方法。此外,您还需要转换运算符。

让我们创建一个名为Logical 的结构体,它有一个int 属性Value

public readonly struct Logical : IEquatable<Logical>
{
    public Logical(int value)
    {
        Value = value == 0 ? 0 : 1;
    }

    public Logical(bool cond)
    {
        Value = cond ? 1 : 0;
    }

    public int Value { get; }

    ... conversions and overrides
}

它有 2 个构造函数,允许您从 intbool 构建一个值。

我们可以声明隐式转换以在boolLogicalintLogicalLogicalbool 之间进行转换。

public static implicit operator Logical(bool cond) => new Logical(cond);

public static implicit operator Logical(int i) => new Logical(i);

public static implicit operator bool(Logical logical) => logical.Value != 0;

重写EqualsGetHashCode 也很好,以便能够轻松地比较值或将它们添加到字典或哈希集。

public bool Equals(Logical other) // Implements IEquatable<Logical>
{
    return Value.Equals(other.Value);
}

public override bool Equals(object obj)
{
    if (obj is Logical logical) {
        return Equals(logical);
    }
    return base.Equals(obj);
}

public override int GetHashCode() => Value.GetHashCode();

如果覆盖Equals,自然会重载==!=

public static bool operator ==(Logical a, Logical b) => a.Value == b.Value;
public static bool operator !=(Logical a, Logical b) => a.Value != b.Value;

最后,我们覆盖 ToString 以便能够打印逻辑。

public override string ToString() => Value == 0 ? "FALSE" : "TRUE";

现在,我们可以做这些事情了:

double x = 3.14;
Logical logical = x > 0.0;
bool b = logical;

Console.WriteLine($"logical = {logical}");
Console.WriteLine($"b       = {b}");

logical = -3;
Console.WriteLine($"logical = {logical}");
Console.WriteLine($"logical.Value = {logical.Value}");
logical = 0;
Console.WriteLine($"logical = {logical}");
Console.ReadKey();

打印出来:

logical = TRUE
b       = True
logical = TRUE
logical.Value = 1
logical = FALSE

您还可以做更多事情。例如,System.Bool 实现了 IComparableIComparable&lt;bool&gt;IConvertibleIEquatable&lt;bool&gt;。它还具有静态 ParseTryParse 方法。您还可以重载其他运算符。请参阅:Overloadable operators (Operator overloading, C# reference)

【讨论】:

  • 谢谢,顺便问一下,我可以直接使用cond as Logical,它会返回10
  • Logical logical = x &gt; 0.0;。布尔条件 x &gt; 0.0 自动转换为 Logical。然后您可以使用logical.Value 访问该值,或者您可以添加转换public static implicit operator int(Logical logical) =&gt; logical.Value; 并写入var i = (int)(Logical)cond;,其中condbool。您还可以更改ToString,使其返回"0""1"。除了创建类型,您还可以在静态类 public static int ToLogicalInt(this bool cond) =&gt; cond ? 1 : 0; 中创建扩展方法并编写 cond.ToLogicalInt()
【解决方案2】:

答案here 可能是您应该使用的答案,除非您有充分的理由不这样做。

但是,仅仅因为它很有趣,您也可以使用以下结构的某个版本,这样转换是隐式的,并且您可以同时使用 bool 值和 int 值,而无需使用任何额外的内存:

[StructLayout(LayoutKind.Explicit)]
public struct BoolToInt
{
    [FieldOffset(0)]
    public readonly bool booleanValue;

    [FieldOffset(0)]
    public readonly int integerValue;

    public BoolToInt(bool booleanValue)
    {
        this.integerValue = 0; //irrelevant, will be overwritten, but the compiler can't figure this out
        this.booleanValue = booleanValue;
    }
}

如果您希望能够更改布尔值,您可以使布尔值可变,但这确实违反了结构使用的一般原则。
我强烈建议不要使 integerValue 字段可变。

【讨论】:

  • 感谢您的回答,所以,我可以使用cond as BoolToInt 表达式,rigjt?
  • 没有。如果你想这样做,你必须使用选择的答案。有了这个,你只需要使用 integerValue 属性,不需要强制转换(as)。
【解决方案3】:

如果您需要布尔值(1 或 0),您应该使用 GetHashCode 函数 Boolea.GetHashCode

我在这里举了一个例子

bool v1 = true;
bool v2 = false;
int res;

Console.WriteLine($"v1: {v1.GetHashCode()}, v2: {v2.GetHashCode()}");

【讨论】:

  • 正如我在链接中提到的,布尔类将 true 实现为整数 1,将 false 实现为整数 0。但是,特定的编程语言可能会用其他值表示真假。
  • 另外,GetHashCode 的实现可能随时改变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 2014-07-01
  • 2019-07-08
  • 2020-11-14
  • 2011-02-27
  • 1970-01-01
  • 2023-04-01
相关资源
最近更新 更多