【问题标题】:Default value check using generic types [duplicate]使用泛型类型检查默认值
【发布时间】:2010-02-02 20:32:53
【问题描述】:

我希望能够检查一个值是否是其值类型的默认值。理想情况下,我想说:

DoSomething<TValue>(TValue value) {
    if (value == default(TValue)) {
        ...
    }
}

但是,编译器抱怨它无法对 TValue 和 TValue 进行== 比较。这是迄今为止我想出的最好的解决方法:

DoSomething<TValue>(TValue value) {
    if (value == null || value.Equals(default(TValue))) {
        ...
    }
}

有没有更优雅/正确的方法来解决这个问题?

【问题讨论】:

    标签: c# generics


    【解决方案1】:
    public bool EqualsDefaultValue<T>(T value)
    {
        return EqualityComparer<T>.Default.Equals(value, default(T));
    }
    

    【讨论】:

    • 不错的一个!它适用于任何类型,甚至可以为空类型?
    • @MariusStănescu 确实!
    • 它是否适用于基于期望的盒装类型是有争议的。 EqualsDefaultValue((object)0) 返回 false。我希望它返回true,因为default(int)0,而int 是参数的运行时类型,即使从技术上讲object 的默认值是null 而不是@ 987654330@
    • @Vikhram:在这种情况下,T 将是object,默认比较器会检查引用相等性。装箱的 default(int) 与装箱的值作为两个不同的引用进行比较。
    【解决方案2】:

    加入类约束,它应该可以工作。

    public void Test<T>(T instance) where T : class
    {
        if (instance == default(T))
        {
    
        }
    }
    

    或者,如果您只想要值类型,您可以这样做。

    public void Test<T>(T instance) where T : struct, IEquatable<T>
    {
        if (instance.Equals(default(T)))
        {
    
        }
    }
    

    【讨论】:

    • 如果你加入class约束,你也可以只检查null...
    • @Marc - 我知道,目前这是一个偏好问题。
    • 我希望让这项工作适用于任何类型,包括值和类类型。
    【解决方案3】:

    除了此处发布的答案之外,我认为我们还应该能够指定您是否需要值或引用相等:

    static public class MyGenericHelper
    {
        static public bool EqualsByValue<T>(T x, T y)
        {
            return EqualityComparer<T>.Default.Equals(x, y);
        }
    
        static public bool EqualsByReference<T>(T x, T y)
        {
            if (x is ValueType) return EqualityComparer<T>.Default.Equals(x, y) // avoids boxing
    
            return Object.ReferenceEquals(x, y);
        }
    }
    

    我们都喜欢创建和维护无数这样的小助手方法,不是吗:->

    【讨论】:

    • 就可读性和性能而言,typeof(T).IsValueType 似乎比x is ValueType 更可取。我错了吗?
    • 也许可读性有时是一个品味问题。 :-> ... x is ValueType 对我来说只是直观地“感觉更快”,因为typeof(T).IsValueType 必须检索相当重的Type 实例,并且反射器显示.IsValueType 属性调用了一个虚拟方法,该方法在RuntimeType 最终称为外部。但那我该判断谁,我不是内幕人士。他们甚至可能编译成相同的指令。也许这是一个很好的新问题。 ;-) ... 或者,如果关键,您可以自己进行一些性能测试。
    • 这并不重要,但我很好奇,所以我做了一个快速测试,你是对的! x is ValueType 大约需要三分之一的时间。
    • 如果x is ValueType 只是return false。在名为EqualsByReference 的方法中进行值比较是没有意义的,因为结构的每个实例都是不同的。或者以其他方式使用class 约束来约束方法。
    【解决方案4】:

    您的问题是泛型类型(没有约束)必须对任何类型都是“可编译的”。由于并非所有类型都有 == 运算符,因此您的代码将无法编译。

    解决它的一种方法是添加一个类约束,但是因为您使用 default(TValue) 会建议您希望代码与其他类型一起使用。 (否则只需使用 null 而不是 default(TValue)。一种解决方案可能类似于 Bryan Watts 建议的内容

    bool DoSomething<TValue>(TValue value) {
        return EqualityComparer<TValue>.Default.Equals(value, default(TValue));
    }
    

    或者你可以把它包装在一个扩展方法中

    bool IsDefault<TValue>(this TValue value) {
        return EqualityComparer<TValue>.Default.Equals(value, default(TValue));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-14
      • 2022-08-05
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      相关资源
      最近更新 更多