2016-09-12 6 views
0

私はいくつかの子クラスを持つ基本クラスを持っています。 各クラスには、指定された列挙型の値を返すGetTypeプロパティがあります。 enum値を指定するとクラス名を取得できますか?リフレクション:提供されたプロパティ値からクラス名を取得

例:

public enum EnumClassNames 
{ 
    Class1 = 1, 
    Class2 = 2, 
} 

class MySubClass : ParentClass 
{ 
    public override EnumType MyType() 
    { 
     return EnumType.Class1; 
    } 
} 

void main() 
{ 
    var className = xxxx(EnumType.Class1); //I would like to get the value MySubClass back here. 
} 

編集: 少し背景。私はキュー内のメッセージを処理するMessage親クラスを持っています。各種類のメッセージサブクラスは、ProcessMessage関数をオーバーライドします。

また、キューを繰り返し処理して各メッセージを処理するキュークラスがあります。したがって、 "正しい"オプションは、おそらくQueueクラス内の各子クラスのオブジェクトを明示的にインスタンス化してChildClass.ProcessMessageを呼び出すことになりますが、追加された新しいMessageTypesのメンテナンスを最小限に抑えるため、子クラスの名前を "そこからオブジェクトをインスタンス化します。これにより、新しいMessageタイプが追加されたときに、if文とswitch文が追加されなくなります。

+1

簡単な答え:これはできません。解決しようとしている実際の問題は何ですか? – Dennis

+0

'ParentClass'のポイントは何ですか?あなたはそのタイプ、または子タイプを取得したいですか? – gobes

+0

ゴブ:この質問のために、親クラスは実際にはあまりしません:)おそらくそれを残している可能性があります。 –

答えて

2

そのメソッドを呼び出すインスタンスが必要なので、私はそのためのメソッドを作成しません。ただし、型を返す静的プロパティを作成することはできます。たぶん、属性がさらに良いかもしれません。私は例として、フィドルを作成

https://dotnetfiddle.net/IweLy7

それは、関連するタイプのためのアセンブリをスキャンに依存しています。もう1つの答えに記載されているように、ユースケースのために追加のアセンブリをチェックする必要があるかもしれません。

+0

説明した静的プロパティの唯一の問題は、コンパイル時にこのようなプロパティの存在を強制する方法がないため、派生クラスにプロパティが含まれていない場合は39行目で失敗します。 – kiziu

+0

これは本当に問題です。しかし、enum値を返すメソッドでは、インスタンスを作成する必要があります。 – Nico

2

あなたはEnumType値を取得し、検索値に対応するサブクラスを見つけるために、メソッドを呼び出して、各派生クラスのインスタンスを作成し、その後、ParentClassから継承するすべてのタイプのAssemblyをスキャンする必要があるとしています。派生したすべての型が同じアセンブリ内にあると仮定します。そうしないと、すべてのアセンブリ/既知のアセンブリをスキャンする必要があります。

あなたが達成しようとしていることをちょっと詳しく説明してください。そうした方がよいでしょう。

+0

私は質問の編集で少し詳しく説明します。 –

+0

アプリケーションにIoCコンテナがある場合は、キー付き登録を使用して、コンテナをメッセージのファクトリとして利用できます。他のオプションは、メッセージタイプの静的な辞書を親クラスの中に格納し、それを本質的に逆転させる(サブクラスはそれ自身を公開する責任がある)すべてのメッセージタイプからそれを移入することですが、それは最善の解決策ではありません。 – kiziu

0

GetType().ToString()メソッドを使用してオブジェクトの種類を取得し、それを列挙型に変換できます。

public override EnumClassNames MyType() 
{ 
    string stringifiedType = this.GetType().ToString(); 

    var myEnumType = (EnumClassNames)Enum.Parse(typeof(EnumClassNames), stringifiedType); 

    return myEnumType; 
} 

変換しようとしているタイプがわからない場合は、Enum.TryParse()メソッドを使用することもできます。

2

編集した質問に応じて、基本的な考えを示します。

// Message types 
class Message { } 
class MessageA : Message { } 
class MessageB : Message { } 

とベースメッセージプロセッサ:あなたは、そのカスタムプロセッサに特定のメッセージタイプをバインドする必要があり

interface IMessageProcessor 
{ 
    void ProcessMessage(Message message); 
} 

abstract class MessageProcessor<TMessage> : IMessageProcessor 
    where TMessage : Message 
{ 
    protected abstract void ProcessMessage(TMessage message); 

    public void ProcessMessage(Message message) 
    { 
     ProcessMessage((TMessage)message); 
    } 
} 

メッセージの種類があることを

と仮定。上記のコードを使用すること、

[MessageProcessor(typeof(MessageA))] 
class MessageAProcessor : MessageProcessor<MessageA> 
{ 
    protected override void ProcessMessage(MessageA message) 
    { 
     Console.WriteLine("Processing A message..."); 
    } 
} 

[MessageProcessor(typeof(MessageB))] 
class MessageBProcessor : MessageProcessor<MessageB> 
{ 
    protected override void ProcessMessage(MessageB message) 
    { 
     Console.WriteLine("Processing B message..."); 
    } 
} 

ここではサンプルキューがあります:

// Mapping attribute 
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
class MessageProcessorAttribute : Attribute 
{ 
    public MessageProcessorAttribute(Type messageType) 
    { 
     MessageType = messageType; 
    } 

    public Type MessageType { get; } 
} 

今、あなたは宣言することができメッセージプロセッサ:これは、カスタム属性を必要とする、つまり、いくつかのメタデータを使用して行うことができる

// Message queue 
class MessageQueue 
{ 
    private readonly Queue<Message> messages; 

    public MessageQueue() 
    { 
     messages = new Queue<Message>(); 
    } 

    public void PostMessage(Message message) 
    { 
     messages.Enqueue(message); 
    } 

    public void ProcessMessages() 
    { 
     while (messages.Any()) 
     { 
      var message = messages.Dequeue(); 
      var messageProcessor = GetMessageProcessorOrDefault(message); 

      messageProcessor?.ProcessMessage(message); 
     } 
    } 

    private IMessageProcessor GetMessageProcessorOrDefault(Message message) 
    { 
     var messageType = message.GetType(); 
     var messageProcessorTypes = GetMessageProcessorTypes(); 
     var messageProcessorType = messageProcessorTypes 
      .FirstOrDefault(mpt => mpt.GetCustomAttribute<MessageProcessorAttribute>()?.MessageType == messageType); 

     return messageProcessorType != null ? (IMessageProcessor)Activator.CreateInstance(messageProcessorType) : null; 
    } 

    private IEnumerable<Type> GetMessageProcessorTypes() 
    { 
     // TODO: scan assemblies to retrieve IMessageProcessor implementations 
     return new[] 
     { 
      typeof(MessageAProcessor), 
      typeof(MessageBProcessor) 
     }; 
    } 
} 

このアプローチをDIコンテナと組み合わせて、プラグインベースのアプリケーション(メッセージタイプとプロセッサの数)を、その場所(同じアセンブリまたは複数のアセンブリ)が行うように構築できます関係なく。

更新。私はすべての子孫に型キャストを避けるためにいくつかのジェネリックを追加しました。

+0

ああ、うわーデニス。ダブルアップします。私は1つ以上の答えを受け入れることができればいいと思うが、今日私はheinzbeinzの答えに行くつもりだ。それはちょっと私に合っています。しかし、同様の問題を抱えている人は、実際には両方のソリューションを見ることができます。 –

関連する問題