簡體   English   中英

反射:從提供的屬性值獲取類名稱

[英]Reflection: Get Class name from supplied property value

我有一個帶有許多子類的基類。 每個類都有一個GetType屬性,該屬性將返回指定的枚舉值。 提供枚舉值時是否可以獲取類名?

例:

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類,它將遍歷Queue並處理每條消息。 因此,“正確”選項可能是在Queue類中顯式實例化每個子類的對象並調用ChildClass.ProcessMessage,但為了最大程度地減少添加新MessageTypes的維護,我想“讀取”子類的名稱,並從那里實例化一個對象。 然后,當添加新的消息類型時,這將防止多余的if-和switch語句。

您將必須在Assembly掃描所有從ParentClass繼承的類型,然后創建每個派生類的實例,調用該方法以獲取EnumType值並找到與搜索到的值相對應的子類。 假定所有派生類型都在同一程序集中-否則,您將必須掃描所有程序集/已知程序集。

詳細說明您要實現的目標,然后肯定會有更好的方法。

我不會為此創建方法,因為您需要一個實例來調用該方法。 但是,您可以創建返回類型的靜態屬性。 也許一個屬性會更好。

我以小提琴為例: https : //dotnetfiddle.net/IweLy7

它依賴於掃描裝配體中的相關類型。 如另一個答案所述,您可能必須檢查用例的其他程序集。

根據您編輯的問題,我給您一個基本的想法。

假設有消息類型:

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

您需要將特定的消息類型綁定到其自定義處理器。 這可以使用一些元數據來完成,也就是說,您需要自定義屬性:

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

    public Type MessageType { get; }
}

現在,您可以聲明消息處理器:

[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...");
    }
}

這是示例隊列,將使用上面的代碼:

// 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容器結合使用,並構建基於插件的應用程序-消息類型和處理器的數量,因為它們的位置(相同的程序集或多個程序集)無關緊要。

更新 我添加了一些泛型,以避免在每個后代中進行類型轉換。

您可以使用GetType().ToString()方法獲取對象的類型,然后將其轉換為枚舉。

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

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

    return myEnumType;
}

如果不確定要轉換的類型,也可以使用Enum.TryParse()方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM