简体   繁体   English

反射:从提供的属性值获取类名称

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

I have a base class with a number of child classes. 我有一个带有许多子类的基类。 Each class have a GetType property that will return a specified enum value. 每个类都有一个GetType属性,该属性将返回指定的枚举值。 Is it possible to get the class name when I supply the enum value? 提供枚举值时是否可以获取类名?

Example: 例:

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.
}

Edit: A little background. 编辑:一点背景。 I have a Message parent class that will process messages in a queue. 我有一个Message父类,它将处理队列中的消息。 Each 'kind-of' message subclass will override a ProcessMessage function. 每个“种类”消息子类都将覆盖ProcessMessage函数。

I also have Queue class that will iterate through the Queue and process each message. 我也有Queue类,它将遍历Queue并处理每条消息。 So the "correct" option will probably be to explicitly instantiate an object of each child class in the Queue class and call ChildClass.ProcessMessage, but to minimise maintenance with new MessageTypes added, I want to "read" the name of the child class and instantiate an object from there. 因此,“正确”选项可能是在Queue类中显式实例化每个子类的对象并调用ChildClass.ProcessMessage,但为了最大程度地减少添加新MessageTypes的维护,我想“读取”子类的名称,并从那里实例化一个对象。 This will then prevent extra if- and switch statements when new Message types are added. 然后,当添加新的消息类型时,这将防止多余的if-和switch语句。

You're going to have to scan the Assembly for all the types that inherit from ParentClass , then create the instance of each derived class, call the method to get the EnumType value and find the subclass that corresponds to the searched value. 您将必须在Assembly扫描所有从ParentClass继承的类型,然后创建每个派生类的实例,调用该方法以获取EnumType值并找到与搜索到的值相对应的子类。 Assuming that all derived types are in the same assembly - otherwise you will have to scan all the assemblies/known assemblies. 假定所有派生类型都在同一程序集中-否则,您将必须扫描所有程序集/已知程序集。

Elaborate a little on what you are trying to achieve, surely there is a better way of doing that then this. 详细说明您要实现的目标,然后肯定会有更好的方法。

I wouldn't create a method for that, as you need an instance to call that method. 我不会为此创建方法,因为您需要一个实例来调用该方法。 You could however create a static property which returns the type. 但是,您可以创建返回类型的静态属性。 Maybe an attribute would even be better. 也许一个属性会更好。

I created a fiddle as an example: https://dotnetfiddle.net/IweLy7 我以小提琴为例: https : //dotnetfiddle.net/IweLy7

It relies on scanning the assembly for relevant types. 它依赖于扫描装配体中的相关类型。 As stated by the other answer you may have to check additional assemblies for your usecase. 如另一个答案所述,您可能必须检查用例的其他程序集。

According to your edited question, I'll give you a basic idea. 根据您编辑的问题,我给您一个基本的想法。

Suppose, that there are message types: 假设有消息类型:

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

and base message processor: 和基本消息处理器:

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

You need to bind particular message type to its custom processor. 您需要将特定的消息类型绑定到其自定义处理器。 This could be done using some metadata, that is, you need custom attribute: 这可以使用一些元数据来完成,也就是说,您需要自定义属性:

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

    public Type MessageType { get; }
}

Now you can declare message processors: 现在,您可以声明消息处理器:

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

Here's sample queue, that will use code from above: 这是示例队列,将使用上面的代码:

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

You can combine this approach with DI-containers and build plugin-based applications - number of message types and processors, as their location (same assembly or several assemblies) doesn't matter. 您可以将此方法与DI容器结合使用,并构建基于插件的应用程序-消息类型和处理器的数量,因为它们的位置(相同的程序集或多个程序集)无关紧要。

UPDATE . 更新 I've added some generics to avoid type casting in every descendant. 我添加了一些泛型,以避免在每个后代中进行类型转换。

You can get the type of an object with the GetType().ToString() method, and then convert it to an enum. 您可以使用GetType().ToString()方法获取对象的类型,然后将其转换为枚举。

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

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

    return myEnumType;
}

You can also use the Enum.TryParse() method if you are not sure of the type you are trying to convert. 如果不确定要转换的类型,也可以使用Enum.TryParse()方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM