インターフェイス/ベースクラスのC#列挙型?
質問
i列挙型に問題があります
基本クラスまたはインターフェイスで列挙型を作成する必要があります(ただし、空のもの)
class Base
{
public enum Test;
// ???
}
そしていくつかの親クラスで異なる列挙型を作成した後
class Parent1
{
public enum Test {A, B, C};
}
class Parent2
{
public enum Test {J, H, K};
}
そして列挙型を使用する必要があるときにメソッドを持つ次のクラスがあります
class Test<T>
{
public void Foo(Test enum)
{
int value = (int) enum;
// ...
}
}
そのようなことを行う方法はありますか?
そうでない場合、すべてのクラスで静的整数を使用する必要があります...
class Parent1
{
public static int A = 0;
public static int B = 5;
public static int C = 7;
}
class Parent2
{
public static int J = 1;
public static int H = 3;
public static int K = 6;
}
class Test<T>
{
public void Foo(int enum)
{
int value = enum;
// ...
}
}
コードの見た目は悪くありません...一部のクラスでは、20個以上の変数を使用する必要があります
解決
抽象サブクラスのようなものはありません(サブクラスで異なる実装を持つことができます)-ジェネリックはオプションかもしれません:
class Base<T> where T : struct {
private T value;
public void Foo(T value) {
this.value = value;
}
}
class Parent1 : Base<Parent1.Enum1> {
public enum Enum1 {A, B, C};
}
class Parent2 : Base<Parent2.Enum2> {
public enum Enum2 { J, H, K };
}
唯一の問題は、enumのみが使用可能であることを強制しないことです-ただし、実行時にこれを行うことができます-たとえば型初期化子で:
static Base() {
if (!typeof(T).IsEnum) throw new InvalidOperationException(
typeof(T).Name + " is not an enum");
}
他のヒント
質問に答えたり、schtumを維持したりするのではなく、なぜ何かが必要であると主張する人々を見つける頻度は驚くべきことです。どちらもなぜ特定の問い合わせは、回答者が実際に回答を知っている別の問い合わせよりも優先して行われました。聞かれていない質問に答えることは何の役にも立ちません。
手元のトピックに戻ると、今朝上記のシナリオに正確にヒットし、インターフェイスまたは基本クラスでEnumを定義してから同じものを再定義できると便利な理由を理解できます。ベースまたはインターフェイスのいずれかから派生したクラスの名前付き列挙。このような設計の1つの用途は、オブジェクトリレーショナルマッピングとコントロールバインディングです。次のように、派生クラスのどのプロパティがどのタイプのコントロールにバインド可能であるかを説明する一連のEnumがある場合があります。
public enum WebControlTextBoxProperties { }
public enum WebControlLabelProperties { }
...など。
適切な継承が有効になるまで、特定の派生クラスにどのプロパティが存在するか正確にはわからないので、ベースまたはインターフェイスで上記の列挙を消費する一貫したメソッドが必要な場合があるため、完全に-Enumがベース/インターフェイスに存在することを定義できるが、派生クラスの特定のコンテキストでどのメンバーを持っているかを正確に定義できることを期待する有効な設計。
VBのようにC#でもこれが可能だったらいいのに、本当に便利な機能だから。
基本クラスで列挙型を宣言し、派生クラスごとに値を変更できる必要があります。つまり、
class MyClass
{
public enum TestEnum { }
public MyClass()
{
}
}
class MyDerivedClass
{
public enum TestEnum { value1, value2, value3 }
public MyDerivedClass()
{
}
}
MyDerviedクラスは、TestEnum.value1、TestEnum.value2、TestEnum.value3にアクセスできますが、MyClassはタイプにのみアクセスできます。
ただし、個人的にはこれを行う利点がありません。基本クラスで列挙型のすべての値を宣言し、クラスごとに必要な値のみを使用します。
ジェームス。
いいえ、できません。
多くの列挙型は多くの場合、設計上の問題を示します(たとえば、多くのスイッチ構成体)。これをリファクタリングする方法の例を参照するには、このリンクを確認してください。条件をポリモーフィズムに置き換える。
いいえ、インターフェースに静的なものを強制する方法はありません。
おそらく、デザインを再考する必要があります。
基本クラスで列挙型を定義できない理由:
class Base
{
public enum Test {A, B, C, J, H, K};
}
派生クラスで列挙型の関連するメンバーのみを使用しますか?
私は仕事中ですので、詳しく説明することはできませんが、これはある程度可能です。以下のコードの欠点は、TextBoxPropertiesやMyCustomTextBoxPropertiesなどの列挙型を連結できないことです:TextboxProperties
コードは次のとおりです。
public enum Test
{
}
public enum ThisTest
{
MyVal1,
MyVal2,
MyVal3
}
public abstract class MyBase
{
public Test MyEnum { get; set; }
}
public class MyDerived : MyBase
{
public new ThisTest MyEnum { get; set; }
}
YOU CAN ENUMを抽象化!
何もチェックせずに物事は不可能だと主張するのはなぜですか?
確かに、.NETドキュメントはこれについて少しあいまいですが、System.Enumクラスはenumの抽象化です。 System.Enumを列挙値のみを受け入れる変数として使用でき、このクラスを介して列挙の名前または値型の値にアクセスできます。
例:
// abstracted enumeration value
Enum abstractEnum = null;
// set to the Console-Color enumeration value "Blue";
abstractEnum = System.ConsoleColor.Blue;
// the defined value of "ConsoleColor.Blue" is "9":
// you can get the value via the ToObject method:
Console.WriteLine((int)Enum.ToObject(abstractEnum.GetType(), abstractEnum));
// or via the GetHashCode() method:
Console.WriteLine(abstractEnum.GetHashCode());
// the name can also be acessed:
Console.WriteLine(Enum.GetName(abstractEnum.GetType(), abstractEnum));
上記のコードの出力:
9
9
青
@Marc Gravellの受け入れられた回答が好きです。 私はstackoverflow-newbieなので、コメントすることはできません。しかし、特にフラグ属性を使用してビットごとのフラグテスト操作を実行する場合は、列挙型の基礎となるタイプも確認すると便利であることを追加したいと思います...
if ( !typeof(T).IsEnum || typeof(int) != Enum.GetUnderlyingType(typeof(T)) )
{
throw new InvalidOperationException( typeof(T).Name + " is not an enum");
}
これが私に役立つ解決策です:
親クラスで、フィールドを列挙ではなくintとして宣言します:
protected int state;
そのため、この値のシリアル化と非シリアル化をディスクに提供するために、親クラスは引き続きこの値をintとして使用できます。
その後、クラスをオーバーライドする人はこれを行うことができます:
enum states{
state1, state2
}
this.state = state1.toInt();
次のように実際の値にアクセスできます:
...
if (this.state == states.state1.toInt()){
...
}
else{
...
}
ここでtoInt()は、静的クラスで次のように定義されます。
public static class Utils
{
public static int toInt(this state s)
{
return (int)s;
}
}