繁体   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