【问题标题】:How can I get a list of constructed generic types?如何获取构造的泛型类型列表?
【发布时间】:2011-01-25 06:53:08
【问题描述】:

我正在开发一个项目(使用 Xna),该项目基本上读取 XML 内容文件以创建处理各种类型输入事件的事件处理程序。 XML 文件如下所示:

<InputMapping>
  <InputType>Microsoft.Xna.Framework.Input.Keys, Microsoft.Xna.Framework, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d</InputType>
  <Combination>Up W</Combination>
  <CombinationType>Any</CombinationType>
  <Handlers>
    <Handler>MoveUp</Handler>
    <Handler>ScrollMenuUp</Handler>
  </Handlers>
</InputMapping>

“MoveUp”和“ScrollMenuUp”是我希望能够处理按下“Up”和/或“W”键时引发的事件的两个方法的名称,并且我已经标记了它们的包含类有一个自定义属性这样说。生成的“输入地图”被添加到游戏中每帧更新的输入地图列表中。当满足输入组合(可能是鼠标按钮单击、滚轮移动、鼠标移动等,取决于输入映射的类型)时,将引发事件并由 XML 中列出的方法处理文件。


为了找到 XML 文件引用的方法,我最初的计划是使用反射迭代执行程序集中的导出类型,找到应用了我的自定义属性的静态类,并存储它们的所有公共静态与 Dictionary 中相关事件的委托签名匹配的方法,以它们的名称为键,以供后续输入映射加载引用相同的方法使用。对于发布版本,我会将此方法列表写入文件以大幅减少加载时间,但对于调试,我希望此可用事件处理程序列表与我的修订保持同步。

这非常有效,而且出乎意料地比我预期的耗时少。但是,我不知道如何扩展这种方法以包含泛型委托:我有一个名为 InputHandler&lt;T&gt; 的泛型委托,如下所示:

public delegate void InputHandler<T>(T input, GameTime gameTime) where T : struct;

我可以很好地获取委托的签名,但我的问题是我不知道如何获取由泛型类型构造的类,这些泛型类型包含可能由InputHandler&lt;T&gt; 表示的方法。更简单地说,我有一个名为 InputHandlers&lt;T&gt; 的类,它看起来像这样:

[MyInputHandlerAttribute]//This tells my XML-loading method to look in this class for event handler candidates
public static class InputHandlers<T>
    where T : struct
{
    public static void HandleInput<T>(T input, GameTime gameTime)
    {
        /*
        * An input event would be handled here.
        * The type of input event handled would depend entirely on the assembly-qualified
        * name provided in the "<InputType>" element of the XML file.
        * This kind of non-specific input handling might not make sense, but it has its worthwhile uses:
        * serializing input for network transmission
        * (using some interface that T would be constrained to implement) is the use I have in mind.
        */
    }
}

并且我希望能够在我的 XML 文件中简单地键入 &lt;Handler&gt;HandleInput&lt;/Handler&gt; 并找到与从 InputHandlers&lt;T&gt; 构造的类中定义的方法相对应的 MethodInfo,其通用参数对应于我正在寻找的事件句柄(与事件的InputHandler&lt;T&gt; 声明中使用的 T 类型相同,我只能从 XML 文件中列出的程序集限定名称派生)。

我知道(根据 C# 规范)在运行时不存在开放类型,那么如何获取从我的泛型类构造的封闭类型的列表?

【问题讨论】:

    标签: generics reflection xna


    【解决方案1】:

    如果我理解正确,您需要根据 XML 文件中指定的字符串值调用通用方法。这样就可以了:

    void Main() {
        HandleEvent ("WindowsBase", "System.Windows.Input.Key");
        // I dont have XNA, so I could not test your specific classes
        // HandleEvent ("Microsoft.Xna.Framework",  "Microsoft.Xna.Framework.Input.Keys"); 
    }
    
    void HandleEvent(string assemblyName, string typeName)
    {   
        var instance = Assembly.Load(assemblyName).CreateInstance(typeName);
        Handler.Handle(instance);
    }
    
    static class Handler {
        public static void Handle<T>(T input)  {
            Console.WriteLine("Handling input of type: " + input.GetType());
        }
    }
    

    您可能想要添加错误处理、空值检查等。

    【讨论】:

    • 谢谢,但这不是我需要的...我需要一种方法来获取 System.Reflection.MethodInfo 对象,该对象代表我的通用方法“HandleInput”在从通用“InputHandlers”类构造的运行时类型。
    • 此外,将“实例”(对象类型)传递给 Handler.Handle 可以避免在方法中使用泛型参数——“T”始终是 System.Object .这几乎可以防止任何有用的类型反射。
    • 我也想知道这个的用处......但是, input.GetType() 确实得到了具体的类型,在这个例子中你得到了输出“处理类型的输入:系统。 Windows.Input.Key"
    • 是的,你是对的——我的错。 GetType() 方法和将传递给方法(例如您的示例中的方法)的隐式参数都将获得任何对象的具体类型。
    【解决方案2】:

    事实证明,我把这个问题过度复杂化了。我真正的问题,虽然我不知道,但如何仅使用类型的名称来获得泛型类型定义(即typeof(InputHandlers&lt;&gt;),没有特定的泛型参数)。这很简单:

    Type genericDefinition = typeof(<some type in my assembly>).Assembly.GetTypes().Where(t=>(t.IsGenericDefinition && t.Name == <the name I'm looking for>)).First();
    

    使用检索到的类型,只需 2 个简单的步骤即可获得具有任何类型参数的类型的“构造”版本,然后找到该类型中定义的静态方法:

    MethodInfo referencedMethod = genericDefinition.MakeGenericType(<the type parsed from the InputType tag of my xml>).GetMethod(<the name of the static method parsed from my xml>);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-12
      • 1970-01-01
      • 2016-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-17
      相关资源
      最近更新 更多