1

重複の可能性:
C# で 2 つの列挙型が等しいのはいつですか?

単純なステート マシンの一部として、次のクラスがあります。

すべてのジェネリック型パラメーターは列挙型でなければならないことに注意してください。これはコンストラクターで強制されています (ここには示されていません)。

// 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);
    }
}

上記はコンパイルされますが、これがジェネリック型パラメーターとして渡された列挙型を処理する正しい方法であるかどうかはわかりません。

注: 比較関数では、順序を考慮する必要はありません。むしろ、正確な重複をチェックする必要があります。

4

2 に答える 2

3

注: 比較関数は順序を気にする必要はありません。むしろ、正確な重複をチェックする必要があります。

その場合、実装するべきではありませんIComparer<T>。実装する必要がありますIEqualityComparer<T>-または、より簡単に、Transition実装する必要がありますIEquatable<Transition>

現在、コードの残りの部分で theを使用していないことに注意してください。TransitionComparer列挙値ごとに独自の比較コードを記述する必要はないように思えます-それらを組み合わせようとしているだけです。残念ながら、enum は を実装していないため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;
    }
}

EDIT:平等のためのボクシングを避けるために、基になる値を取得するためにある種のデリゲートが必要になると思います(そして、異なる基になる型で値をサポートする必要がある場合、それはかなり苦痛です)または使用するUnconstrained Melodyのようなものを使用する可能性がありますコンパイル時に制約を適用するように IL を書き換え、基礎となる値に基づいてより効率的に等価性をチェックできるようにします。

于 2012-09-24T05:59:32.763 に答える
-1

以外何も見えない

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

列挙型はボックス化されています。どうすればこれを回避できるかわかりません。

于 2012-09-24T06:02:37.177 に答える