ICAMarable与作为泛型类型参数发送的枚举(C#)

时间:2012-09-24 05:29:13

标签: c# .net generics enums icomparer

  

可能重复:
  When are two enums equal in C#?

我将以下类作为简单状态机的一部分。

请注意,所有泛型类型参数都必须是枚举。这已在构造函数中强制执行(此处未显示)。

// Both [TState] and [TCommand] will ALWAYS be enumerations.
public class Transitions<TState, TCommand>: List<Transition<TState, TCommand>>
{
    public new void Add (Transition<TState, TCommand> item)
    {
        if (this.Contains(item))
            throw (new InvalidOperationException("This transition already exists."));
        else
            this.Add(item);
    }
}

// Both [TState] and [TCommand] will ALWAYS be enumerations.
public class Transition<TState, TCommand>
{
    TState From = default(TState);
    TState To  = default(TState);
    TCommand Command = default(TCommand);
}

public sealed class TransitionComparer<TState>:
    IComparer<TState>
{
    public int Compare (TState x, TState y)
    {
        int result = 0;

        // How to compare here since TState is not strongly typed and is an enum?
        //    Using ToString seems silly here.

        result |= x.From.ToString().CompareTo(y.From.ToString());
        result |= x.To.ToString().CompareTo(y.To.ToString());
        result |= x.Command.ToString().CompareTo(y.Command.ToString());

        return (result);
    }
}

以上编译但我不确定这是否是处理作为泛型类型参数传入的枚举的正确方法。

注意:比较功能不需要记住订购。相反,它需要检查确切的重复。

2 个答案:

答案 0 :(得分:3)

  

注意:比较功能不需要记住订购。相反,它需要检查确切的重复。

在这种情况下,您不应该实施IComparer<T>。您应该实施IEqualityComparer<T> - 或者更简单地说,Transition实施IEquatable<Transition>

请注意,就我们所见,您目前尚未在其余代码中使用 TransitionComparer。听起来你不应该真的需要为每个枚举值编写自己的比较代码 - 你只是想把它们组合起来。不幸的是,枚举没有实现IEquatable<T>,这使得在没有装箱的情况下更难做到这一点 - 这对性能至关重要吗?

以下是Transition的示例等式实现:

public class Transition<TState, TCommand>
    : IEquatable<Transition<TState, TCommand>>
{
    // I assume in reality these are properties?
    TState From = default(TState);
    TState To  = default(TState);
    TCommand Command = default(TCommand);

    public override bool Equals(object other)
    {
        return Equals(other as Transition<TState, TCommand>);
    }

    public bool Equals(Transition<TState, TCommand> other)
    {
        if (other == null)
        {
            return false;
        }
        return From.Equals(other.From) &&
               To.Equals(other.To) &&
               Command.Equals(other.Command);
    }

    public int GetHashCode()
    {
        int hash = 17;
        hash = hash * 31 + From.GetHashCode();
        hash = hash * 31 + To.GetHashCode();
        hash = hash * 31 + Command.GetHashCode();
        return hash;
    }
}
编辑:为了避免拳击是否相等,我怀疑你要么需要某种代理来获取基础值(如果你需要支持不同底层类型的值,那就太痛苦了)可能使用类似Unconstrained Melody的东西,它使用IL重写在编译时强制执行约束,并允许您更有效地检查基础值的相等性。

答案 1 :(得分:-1)

我看不到任何东西而不是

(int)(object)x.From.CompareTo((int)(object)y.From);

枚举是盒装的。我不知道如何避免这种情况。