Reputation: 2436
I'm working on a project (using Xna) that, basically, reads an XML content file to create event handlers that handle various types of input events. The XML file looks something like this:
<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" and "ScrollMenuUp" are the names of two methods that I want to be able to handle the event raised when the "Up" and/or "W" keys are pressed, and I've marked their containing class with a custom attribute saying so. The generated "input map" is added to a list of input maps which are updated every frame in the game. When an input combination (which may be a mouse button click, a scroll wheel movement, a mouse movement, etc., depending on the type of the input mapping) is satisfied, an event is raised and handled by the methods listed in the XML file.
To find the methods referenced by the XML file, my plan was originally to iterate over the exported types in the executing assembly using reflection, find the static classes that had my custom attribute applied to them, and store all of their public static methods that matched the delegate signature of the event in question in a Dictionary, keyed by their names for use by subsequent input map loads referencing the same methods. For the release build, I'll write this list of methods to a file to massively reduce the loading time, but for debugging I want this list of available event handlers to stay up-to-date with my revisions.
This works perfectly, and is surprisingly less time-consuming than I anticipated. However, I can't figure out how to extend this approach to include generic delegates: I have a generic delegate called InputHandler<T>
that looks like this:
public delegate void InputHandler<T>(T input, GameTime gameTime) where T : struct;
I can get the signature of the delegate just fine, but my problem is that I don't know how to get the classes that are constructed from generic types that contain methods that might be representable by InputHandler<T>
. In more simple terms, I have a class called InputHandlers<T>
that looks like this:
[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.
*/
}
}
and I want to be able to simply type <Handler>HandleInput</Handler>
in my XML file and find the MethodInfo that corresponds to the method defined in the class constructed from InputHandlers<T>
with the generic argument corresponding to the event I'm looking to handle (the same type as T used in the InputHandler<T>
declaration of the event, which I can only derrive from the assembly-qualified name listed in the XML file).
I know (from the C# specifications) that open types don't exist at runtime, so how can I get a list of the closed types constructed from my generic class?
Upvotes: 0
Views: 173
Reputation: 2436
It turns out I was massively over-complicating this issue. My real question, though I didn't know it, was how to get a generic type definition (i.e. typeof(InputHandlers<>)
, without a specific generic parameter) using just the name of the type. That's easy:
Type genericDefinition = typeof(<some type in my assembly>).Assembly.GetTypes().Where(t=>(t.IsGenericDefinition && t.Name == <the name I'm looking for>)).First();
Using the retrieved type, it's just 2 simple steps to get a "constructed" version of the type with whatever type parameter, and then find a static method defined in the type:
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>);
Upvotes: 0
Reputation: 2935
If I understand you correctly, you need to call a generic method based on string values specified in your XML file. This will do the trick:
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());
}
}
You'll probably want to add error handling, null checking and so on.
Upvotes: 1