【问题标题】:Compare two System.Enum of type T比较两个 T 类型的 System.Enum
【发布时间】:2015-04-28 20:40:24
【问题描述】:

我现在已经非常接近了解泛型了(我认为)。
但是,只是认为 System.Enum 不容易实现为泛型类型。 我有这门课:

public class Button<TEnum> where TEnum : struct, IConvertible, IComparable, IFormattable {
   public TEnum Identifier {
        get;
        private set; //Set in the ctor
    }
}

public abstract class AbstractInputDevice<TEnum> where TEnum : struct, IConvertible, IComparable, IFormattable {

   private List<Button<TEnum>> _buttons = new List<Button<TEnum>>();

   public Button<TEnum> GetButton(TEnum Identifier){
        foreach(Button<TEnum> button in _buttons){
            if(button.Identifier == Identifier) //<- compiler throws
                return button;
        }
        Debug.Log("'" + GetType().Name + "' cannot return an <b>unregistered</b> '" + typeof(Button<TEnum>).Name + "' that listens to '" + typeof(TEnum).Name + "." + Identifier.ToString() + "'.");
        return null;
    }
}

InputDevice 可能如下所示:

public class Keyboard : AbstractInputDevice<KeyCode> {
    private void Useless(){
        Button<KeyCode> = GetButton(KeyCode.A);
    }
}

编译器在这里抛出编译错误:

if(button.Identifier == Identifier) //In AbstractInputDevice above

我相信我无法比较这两个 TEnum,因为它们实际上并不知道是 Enum。
因此没有可用的比较方法。

我使用了这个资源:
Create Generic method constraining T to an Enum

感谢任何更好的解决方案或修复。
(但我想保留 Enum 条目作为 GetButton(EnumEntry) 的参数)

【问题讨论】:

  • 编译器给出的确切错误是什么?
  • 你可以试试button.Identifier.Equals(Identifier),让事情更简洁:var button = _buttons.Where(b =&gt; b.Identifier.Equals(Identifier)).FirstOrDefault();
  • @RonBeyer 我使用 Unity3D,他们的编译器有时有点混乱。现在它说“意外符号'=='”,好像会有错字。但在进行一些更改之前,它表示“'==' 不能应用于 'TEnum 和 'TEnum' 类型的操作数”之类的不同内容
  • 我想说你需要创建一个MCVE
  • @Alex 你是认真的吗?没有错误了!

标签: c# generics enums comparison


【解决方案1】:

代替不可能

button.Identifier == Identifier

你应该使用

EqualityComparer<TEnum>.Default.Equals(button.Identifier, Identifier)

这避免了将值装箱到object 框(或IComparable 框)中。

【讨论】:

  • 比较好,同意
  • 好的,既然亚历克斯同意了这个解决方案(我已经将他标记为答案),我将改为标记这个。
  • @NoelWidmer 您仍然可以像 Alex 建议的那样使用 Linq _buttons.FirstOrDefault(b =&gt; EqualityComparer&lt;TEnum&gt;.Default.Equals(b.Identifier, Identifier)),但这更多的是风格和个人喜好问题。
  • 有趣的是EqualityComparer(of enumType).Default 避免了装箱,因为枚举类型没有实现IEquatable(themselves)。我想知道EqualityComparer(of T).Default 除了IEquatable 还找什么?
  • @supercat 只需查看.Default 实例的运行时类型就可以提供一些线索。对于枚举类型E,我得到System.Collections.Generic.EnumEqualityComparer`1[E],因此存在对枚举的特殊支持。鉴于此,他们肯定会小心并避免拳击。对于实现IEquatable`1[G] 的结构G,我得到System.Collections.Generic.GenericEqualityComparer`1[G]。最后,对于没有泛型相等支持的结构N,我得到System.Collections.Generic.ObjectEqualityComparer`1[N]补充: 使用 .NET 4.5.2。
【解决方案2】:

您正在尝试对值类型(结构)执行引用比较,请改用Equals 来表示相等:

public Button<TEnum> GetButton(TEnum Identifier) {
    var button = _buttons
        .Where(b => EqualityComparer<TEnum>.Default.Equals(b.Identifier, Identifier))
        .FirstOrDefault();

    if (button == null)
        Debug.Log("'" + GetType().Name + "' cannot return an <b>unregistered</b> '" + typeof(Button<TEnum>).Name + "' that listens to '" + typeof(TEnum).Name + "." + Identifier.ToString() + "'.");
    return button;
}

无法执行button.Identifier == Identifier 语句,因为结构不存在== 运算符。在一个类上,它会执行参考比较。

正如@JeppeStigNielsen 在他的answer 中指出的那样,为了防止拳击相等比较,最好使用EqualityComparer&lt;TEnum&gt;.Default.Equals 方法。

【讨论】:

  • .Equals() 就像 cmets 中所说的那样工作。但我不明白我应该如何实现你在我的 if 语句中发布的这条新行......
  • @NoelWidmer 在您原来的 GetButton 方法的上下文中添加了它。
  • 是 List.Where 扩展方法?如果是这样,您知道它在哪个命名空间中吗? (不被识别为_buttons的成员)
  • @NoelWidmer 是的,您需要添加 using System.Linq; 声明
  • 确实——我愿意。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多