2

複数の数値(レジスタ値)がある場合があります。読みやすさを向上させ、適切なタイプをチェックしたい(特定の関数では特定の値のみが意味をなします)。

私の特定の実装では、それらを列挙型にしたので、今は列挙型のセットがあります。

特定のアプリケーションの有効な列挙型のセットに分割したいので、このアプローチの終わりに到達したようです-したがって、関数Aは、たとえば、enumA、enumB、およびenumCを入力として取得できますが、enumDは取得できませんこれは、さまざまな機能の説明です。

インターフェイスの列挙型と列挙型の継承についてはすでに調べました。どちらも行き止まりであり、C#では不可能です。

この問題の解決策はどのように見えるのだろうか。可能な値についてインテリセンスを取得し、型の安全性も確保して、(少なくとも悪意を持ってキャストしない限り)で間違った値をフィードできないようにしたいと思います。

これを達成する方法は?

(可能な解決策は、いくつかの異なる列挙型をとるいくつかの関数を単純に記述することです-それでも可能ですが、実際には良くありません、またはこのパターンの名前はありますか?(異なるタイプの "params"引数を使用したC#コンパイル時の型安全性) -どちらもあまり良くないようです。)

4

4 に答える 4

4

1つのオプションは、列挙型をスクラップし、列挙型を模倣するように設計された独自のクラスを使用することです。それらを設定するのは少し手間がかかりますが、一度設定すると、使いやすくなり、説明した機能を使用できるようになります。

public class Register
{
    private int value;

    internal Register(int value)
    {
        this.value = value;
    }

    public static readonly Register NonSpecialRegister = new Register(0);
    public static readonly Register OtherNonSpecialRegister = new Register(1);

    public static readonly SpecialRegister SpecialRegister 
        = SpecialRegister.SpecialRegister;
    public static readonly SpecialRegister OtherSpecialRegister 
        = SpecialRegister.OtherSpecialRegister;

    public override int GetHashCode()
    {
        return value.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        Register other = obj as Register;
        if (obj == null)
            return false;

        return other.value == value;
    }
}

public class SpecialRegister : Register
{
    internal SpecialRegister(int value) : base(value) { }

    public static readonly SpecialRegister SpecialRegister = new SpecialRegister(2);
    public static readonly SpecialRegister OtherSpecialRegister = new SpecialRegister(3);
}

これを考えると、次のような方法があります。

public static void Foo(Register reg)
{
}

これは任意のレジスターを取ることができ、次のように呼び出すことができます。

Foo(Register.NonSpecialRegister);
Foo(Register.OtherSpecialRegister);

次に、次のような別の方法を使用できます。

public static void Bar(SpecialRegister reg)
{
}

これは、を受け入れることはできませんがRegister.NonSpecialRegisterRegister.OtherSpecialRegisterまたはを受け入れることはできSpecialRegister.SpecialRegisterます。

于 2013-03-06T17:50:26.260 に答える
1

CLRの静的型システムの機能を使い果たしたようです。各整数を、格納しようとしている値が実際に静的セットのメンバーであることを検証するクラスでラップすることにより、実行時の検証を引き続き取得できます。

信頼性の高いテストスイートを使用している場合、または手動テストを実行する場合は、サイレントデータの破損を引き起こすバグではなく、少なくともバグを検出できます。

分離したい複数の「セット」がある場合は、クラス継承を使用するか、実行時に変換が正常であることを検証するユーザー定義の変換演算子のセットを使用できます。

特定の要件はわかりませんが、クラスベースの継承を使用して、いくつかのプロパティを静的にチェックできる可能性があります。その場合、基本クラスはより大きなセットになり、派生クラスは許可された値のセットを特殊化します。

于 2013-03-06T17:35:34.147 に答える
1

基本的に2つのオプションがあります。

オプション1:複数の列挙型

アプリケーションごとに1つずつ、複数の列挙型を作成し、各列挙型の値を複製します。次に、それらの間でキャストできます。例えば:

enum App1
{
    Data1 = AppAll.Data1,
    Data2 = AppAll.Data2,
    Data42 = AppAll.Data42,
}

enum App2
{
    Data2 = AppAll.Data2,
    Data16 = AppAll.Data16,
    Data42 = AppAll.Data42,
}

enum AppAll
{
    Data1 = 1,
    Data2 = 2,
    Data16 = 16,
    Data42 = 42,
}

App1 value1 = (App1)AppAll.Data2;
App2 value2 = (App2)value1;

これにより、IntelliSenseが提供されます。

オプション2:許可するものを決定する

値が許可されているブール値を返すメソッドを作成します(これは仮想であり、アプリケーションごとにオーバーライドされる場合があります)。次に、列挙値が間違っている場合に例外をスローできます。

public bool IsAllowed(AppAll value)
{
    return value == AppAll.Data2
        || value == AppAll.Data16
        || value == AppAll.Data42;
}


if (!IsAllowed(value))
    throw new ArgumentException("Enum value not allowed.");

これでは、IntelliSenseは提供されません。


いくつかの注意:

  • structsカバーの下では列挙型は(つまり値型)として表されるため、列挙型を継承することはできません。
  • C#では、列挙型のメンバーでなくても、文字通り任意の値を列挙型にキャストできます。たとえば、(App1)1337値を持つメンバーがいない場合でも実行できます1337
于 2013-03-06T17:35:48.023 に答える
1

コンパイル型のチェックが必要な場合は、個別のケースに対して個別の列挙型を使用することをお勧めします。すべての可能性を備えたマスター列挙型が必要な場合は、すべての「子」列挙型リストがマスターの有効なサブセットであることを確認するテストを作成できます(Intキャストの観点から)。

別の方法として、各列挙型オプションのメソッドを備えたオブジェクトをより適切に提供できないかどうか疑問に思う必要があります(コードが提供されていないため、疑問に思うだけです)。次に、列挙型ではなく、さまざまなメソッドを使用してオブジェクトを継承します。(結局のところ、メソッドシグネチャのプロキシとして列挙型を使用しているようです)。

于 2013-03-06T17:37:41.547 に答える