【问题标题】:Return Type using Generics使用泛型返回类型
【发布时间】:2014-08-25 14:11:51
【问题描述】:

首先,我们非常欢迎关于更好标题的建议。

我刚开始学习泛型,所以我的知识有点有限。我要做的是通过调用方法而不传递任何参数来返回类型。

我失败的部分是试图将我的课程转换为 T。

这是我的代码

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

我想要返回的是类型,这样我就可以在我的类中获得一个静态变量,而不必说我想要它来自哪个类。 所以基本上我想说

DebugEvent.description

不必指定类,因为我有几个不同的。

ReturnSelectedEvent<???>().description

我的 DebugEvent 是 BaseEvent 的子级,并通过声明自己的方式隐藏 BaseEvent 的描述。

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

我希望我说清楚了,并且我正在尝试做的事情是可能的。

我试图用泛型解决的问题是我在代码中多次调用以下代码。

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;

类似这样的东西

toolTip = ReturnSelectedEvent().description;

编辑:

我要解释一下我所追求的。

上面的系统用于菜单,基本上我有一个下拉菜单,我可以从中选择一个项目。此菜单中的选项基于 Enum,即 EventItems

现在取决于我选择哪一个,我希望下面的描述匹配。描述作为静态字符串保存在 BaseEvent 中,然后我将其隐藏/“覆盖”在我的子事件中,使用更匹配该类型事件的一个。

现在我的想法是我可以比较枚举,并根据它是什么,返回相应的类型,以便我可以设置正确的描述。 然后我计划稍后使用相同的方法。 以下是我目前陷入的混乱,我希望有办法解决它

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

我希望我可以将所有不同的方法转换为一个单一的方法,它会做同样的事情,但更短,可能看起来像这样

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

希望这能让事情更清楚,xxObject 方法也将实例化的事件添加到列表中。

所以我的想法是不可能的?如果不是,是否有其他替代方法的提示?

【问题讨论】:

  • 我不认为你所要求的是可能的 - 采取你的最后一行:ReturnSelectedEvent().description - 编译器/运行时此时无法知道返回给你的类型 - 所以你需要给它:ReturnSelectedEvent&lt;DebugEvent&gt;().description - 但是,这样做的意义在哪里?
  • EventItem(?)Handler 不能知道它的事件以及它的描述吗?然后你只需要改用tooltip = switchedItem.Event.Description

标签: c# generics methods types


【解决方案1】:

这对于泛型是不可能的。

泛型方法就像占位符一样工作。占位符必须在调用时填写。现在您正试图将 Type BaseEvent 转换为 T 类型的实例,这是完全错误的,没有任何意义。并且方法签名说该方法返回一个 T 的实例(你应该在调用时传递它)-->废话。

您尝试做的是拥有inheritance over static properties,这是不可能的:

但是:您的 EventList 中有什么?事件实例?还是类型?如果实例(这将是更多的逻辑,因为事件是定义实例)你可以这样做:为事件描述或抽象属性描述创建一个非静态的 Getter 方法,你的问题就解决了。

tooltip = eventList.GetDescription();

【讨论】:

    【解决方案2】:

    我认为您不想要类型,而是 T 的实例。 你必须告诉你的泛型方法有一个默认构造函数:

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

    然后,如果您愿意,例如获取DebugEvent,您可以使用:

    ReturnSelectedEvent<DebugEvent>();
    

    如果您真的想使用模板化工厂,请给它更多逻辑。例如,在函数中添加一些参数,让您在未处于调试模式时切换为 null。

    【讨论】:

    • 你能说明如何调用它吗?在按 OP 要求调用此方法时,您对省略类型有什么建议吗?
    • 你必须像 ReturnSelectedEvent&lt;MyEvent&gt;() 这样称呼它 - 所以最后是:new MyEvent() ;)
    • 答案编辑了调用示例+一些解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多