简体   繁体   中英

Return Type using Generics

First, suggestions for a better title are more than welcome.

I'm just starting to learn about Generics so my knowledge is kind of limited. What I'm trying to do is return a Type by calling a method without passing any parameters.

The part I'm failing at is trying to convert my class to T.

Here's my code

private T ReturnSelectedEvent<T>() where T : BaseEvent
{
    switch (eventList)
    {
        case EventItems.Debug: return (T)((object)typeof(DebugEvent));
    }
    return (T)((object)typeof(BaseEvent));
}

What I want to be returned is the Type so that I may get a static variable in my Class without having to say which class I want it from. So basically I want to say

DebugEvent.description

Without having to specify the Class, as I have several different of them.

ReturnSelectedEvent<???>().description

My DebugEvent is a child of BaseEvent and is hiding BaseEvent's description by declaring its own.

public class DebugEvent : BaseEvent
{
    public static new string description = "This event will fire a debug message when called";
}

I hope I made myself clear, and that what I'm trying to do is possible.

The mess I'm trying to fix with generics is me calling the following multiple times in code.

case EventItems.ToggleEventHandler: toolTip = ToggleEventHandlerEvent.description; break;
case EventItems.PlayerDamage: toolTip = PlayerDamageEvent.description; break;
case EventItems.ControlRestriction: toolTip = ControlRestrictionEvent.description; break;
case EventItems.PlayerForceMove: toolTip = PlayerForceMoveEvent.description; break;

to something more like this

toolTip = ReturnSelectedEvent().description;

EDIT:

Going to explain a bit more of what I'm after.

The system above is used for a menu, basically I have a drop down menu from which I select an item. The options in this menu are based on an Enum, which is the one called EventItems

在此处输入图片说明

Now depending on which one I select, I want the description below to match. The description is saved in the BaseEvent as a static string, which I then hide/"override" in my child event with one that better matches that type of event.

Now my idea is that I could possibly compare the enum and depending on what it is, return the corresponding type so that I may set the proper description. I then plan on using the same method later. The following is the current mess I'm stuck in, and I was hoping there would be a way to clear it up

if (GUILayout.Button("Add to end"))
                    {
                        switch (eventList)
                        {
                            case EventItems.Debug: AddObject<DebugEvent>(); break;
                            case EventItems.Sound: AddObject<SoundEvent>(); break;
                            case EventItems.ToggleEventHandler: AddObject<ToggleEventHandlerEvent>(); break;
                            case EventItems.PlayerDamage: AddObject<PlayerDamageEvent>(); break;
                            case EventItems.ControlRestriction: AddObject<ControlRestrictionEvent>(); break;
                            case EventItems.PlayerForceMove: AddObject<PlayerForceMoveEvent>(); break;
                            case EventItems.CameraFocus: AddObject<CameraFocusEvent>(); break;
                            case EventItems.CameraState: AddObject<CameraStateEvent>(); break;
                            case EventItems.DestroyObject: AddObject<DestroyObjectEvent>(); break;
                            case EventItems.PlayerMoveState: AddObject<PlayerMoveStateEvent>(); break;
                        }
                    }
                    if (GUILayout.Button("Insert before"))
                    {
                        switch (eventList)
                        {
                            case EventItems.Debug: InsertObject<DebugEvent>(loc); break;
                            case EventItems.Sound: InsertObject<SoundEvent>(loc); break;
                            case EventItems.ToggleEventHandler: InsertObject<ToggleEventHandlerEvent>(loc); break;
                            case EventItems.PlayerDamage: InsertObject<PlayerDamageEvent>(loc); break;
                            case EventItems.ControlRestriction: InsertObject<ControlRestrictionEvent>(loc); break;
                            case EventItems.PlayerForceMove: InsertObject<PlayerForceMoveEvent>(loc); break;
                            case EventItems.CameraFocus: InsertObject<CameraFocusEvent>(loc); break;
                            case EventItems.CameraState: InsertObject<CameraStateEvent>(loc); break;
                            case EventItems.DestroyObject: InsertObject<DestroyObjectEvent>(loc); break;
                            case EventItems.PlayerMoveState: InsertObject<PlayerMoveStateEvent>(loc); break;
                        }
                    }
                    if (GUILayout.Button("Insert after"))
                    {
                        switch (eventList)
                        {
                            case EventItems.Debug: InsertObject<DebugEvent>(loc + 1); break;
                            case EventItems.Sound: InsertObject<SoundEvent>(loc + 1); break;
                            case EventItems.ToggleEventHandler: InsertObject<ToggleEventHandlerEvent>(loc + 1); break;
                            case EventItems.PlayerDamage: InsertObject<PlayerDamageEvent>(loc + 1); break;
                            case EventItems.ControlRestriction: InsertObject<ControlRestrictionEvent>(loc + 1); break;
                            case EventItems.PlayerForceMove: InsertObject<PlayerForceMoveEvent>(loc + 1); break;
                            case EventItems.CameraFocus: InsertObject<CameraFocusEvent>(loc + 1); break;
                            case EventItems.CameraState: InsertObject<CameraStateEvent>(loc + 1); break;
                            case EventItems.DestroyObject: InsertObject<DestroyObjectEvent>(loc + 1); break;
                            case EventItems.PlayerMoveState: InsertObject<PlayerMoveStateEvent>(loc + 1); break;
                        }
                        loc++;
                    }
                    if (GUILayout.Button("Replace"))
                    {
                        switch (eventList)
                        {
                            case EventItems.Debug: ReplaceObject<DebugEvent>(); break;
                            case EventItems.Sound: ReplaceObject<SoundEvent>(); break;
                            case EventItems.ToggleEventHandler: ReplaceObject<ToggleEventHandlerEvent>(); break;
                            case EventItems.PlayerDamage: ReplaceObject<PlayerDamageEvent>(); break;
                            case EventItems.ControlRestriction: ReplaceObject<ControlRestrictionEvent>(); break;
                            case EventItems.PlayerForceMove: ReplaceObject<PlayerForceMoveEvent>(); break;
                            case EventItems.CameraFocus: ReplaceObject<CameraFocusEvent>(); break;
                            case EventItems.CameraState: ReplaceObject<CameraStateEvent>(); break;
                            case EventItems.DestroyObject: ReplaceObject<DestroyObjectEvent>(); break;
                            case EventItems.PlayerMoveState: ReplaceObject<PlayerMoveStateEvent>(); break;
                        }
                        loc++;
                    }

I was hoping I could switch out all the different methods to one single one, that would do the same thing, but musch shorter, possibly looking like this instead

AddObject<ReturnSelectedEvent()>();
InsertObject<ReturnSelectedEvent(loc)>();
AddObject<ReturnSelectedEvent(loc + 1)>();

Hopefully this makes things clearer, also the xxObject methods adds an instantiated Event to a List.

So what I was thinking is not possible? If it isn't, any tips for alternative ways of doing this?

I think you don't want the type but an instance of T . you have to tell your generic method there is a default constructor :

     private T ReturnSelectedEvent<T>() where T : BaseEvent, new()
     {
        return new T();
     }

Then if you want, for example get a DebugEvent you can use :

ReturnSelectedEvent<DebugEvent>();

If you really want to use a templated factory, give it a bit more logic. For example, add some parametter in the function that will allow you to switch to null if you're not in debug mode.

this is not possible with generics.

The generic methods are working like a placeholder. The placeholder has to be filled at the moment of the call. Now your are trying to cast the Type BaseEvent to an instance of type T, which is totally wrong and makes no sense. And the method signature says that the method returns an instance of T (which you should pass on call) --> nonsense.

What you try to do is having inheritance over static properties , this is not possible:

But: What do you have in your EventList? Instances of events? Or Types? If instances (which would be way more logic as events are by definition instances) you could do: Create a non-static Getter Method for the events description or an abstract property Description and your problem is solved.

tooltip = eventList.GetDescription();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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