【问题标题】:Can I have a C# generic constraint on "operator true"?我可以对“operator true”有一个 C# 通用约束吗?
【发布时间】:2020-06-25 16:42:48
【问题描述】:

假设我有一个包含布尔值列表的类,并且我想要一个属性来报告它们是否都是“真”。有几种方法可以做到这一点:

class BunchOfBools
{
    List<bool> Stuff = new List<bool>();
    bool AllAreTrue1 => Stuff.All(b => b);
    bool AllAreTrue2 => Stuff.TrueForAll(b => b);
}

酷。生活是美好的。

但现在我意识到我有一个实现“operator true”和“operator false”的类

class BatteryIsGood
{
   float BatteryVoltage;

   public static bool operator true(BatteryIsGood ab) => ab.BatteryVoltage >= 3;
   public static bool operator false(BatteryIsGood ab) => ab.BatteryVoltage < 3;
}

如果我有一堆“BatteryIsGood”对象(是的,这是一个人为的例子)并且我想使用 BunchOfBools 来检查它们是否都很好 - 所以让 BunchOfBools 通用:

class BunchOfBools<T>
{
    List<T> Stuff = new List<T>();
    bool AllAreTrue1 => Stuff.All(b => b);
    bool AllAreTrue2 => Stuff.TrueForAll(b => b);
    bool AllAreTrue3 => Stuff.All(b => (bool)b);
    bool AllAreTrue4 => Stuff.TrueForAll(b => (bool)b);
    bool AllAreTrue5
    {
        get
        {
            foreach (T one in Stuff)
            {
                if (!one)
                    return false;
            }
            return true;
        }
    }
    bool AllAreTrue6 => Stuff.All(b => (bool)(object)b);
    bool AllAreTrue7 => Stuff.TrueForAll(b => (bool)(object)b);
}

BunchOfBools<BatteryIsGood> allBatteriesAreGood;

当然,编译器对泛型 BunchOfBools(函数 1 到 5 无法编译)一点也不满意,因为“无法将类型 'T' 转换为 bool”。 AllAreTrue6 和 AllAreTrue7 可以编译,但 (1) 丑陋,(2) 效率低下,以及 (3) 不是类型安全的(直到运行时才会发现 'T' 不能转换为 bool)。

有没有办法添加一个通用的约束,上面写着“T 必须实现 operator true”?

编辑

如果有帮助的话,甚至可以说类必须实现到 bool 的隐式转换:

class BatteryIsGood
{
   float BatteryVoltage;

   public static bool operator true(BatteryIsGood ab) => (bool)ab;
   public static bool operator false(BatteryIsGood ab) => !((bool)ab);

   public static implicit operator bool(BatteryIsGood big) => ab.BatteryVoltage >= 3;
}

【问题讨论】:

  • 可能不是最优雅的,但答案有效吗?

标签: c# boolean operator-overloading


【解决方案1】:

您可以结合使用 ToString 和 Parse,如下所示:

class BunchOfBools<T>
{
    List<T> Stuff = new List<T>();
    bool AllAreTrue1 => Stuff.All(b => bool.Parse(b.ToString()));
    bool AllAreTrue2 => Stuff.TrueForAll(b => bool.Parse(b.ToString()));
    bool AllAreTrue3 => Stuff.All(b => (bool)bool.Parse(b.ToString()));
    bool AllAreTrue4 => Stuff.TrueForAll(b => (bool)bool.Parse(b.ToString()));
    bool AllAreTrue5
    {
        get
        {
            foreach (T one in Stuff)
            {
                if (!bool.Parse(one.ToString()))
                    return false;
            }
            return true;
        }
    }
    bool AllAreTrue6 => Stuff.All(b => (bool)(object)b);
    bool AllAreTrue7 => Stuff.TrueForAll(b => (bool)(object)b);
}

【讨论】:

  • 这里有几个问题 - (1) 您现在要求“ToString”准确返回“true”或“false”。由于 T 可能是一个任意复杂的对象,这可能是不合理的。 (2) 您仍然没有编译时安全性 - 在您访问该属性之前您不会知道 T 是否满足您的需求。
  • 哦,好吧 - 猜猜他们是休息时间。
猜你喜欢
  • 2019-10-14
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
  • 1970-01-01
  • 2011-03-11
相关资源
最近更新 更多