This repository was archived by the owner on Feb 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Add invocation helpers for (generic) methods (on generic types) #89
Open
Banane9
wants to merge
10
commits into
neos-modding-group:master
Choose a base branch
from
Banane9:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
4d0d8b1
Add invocation helpers for (generic) methods (on generic types)
Banane9 b1e5eff
access oopsie
Banane9 7c73e42
Concrete Version number
Banane9 2eac690
Merge branch 'master' into master
zkxs e69cef6
Improve logging in GetGenericMethodOfConcreteType
Banane9 8b38b7a
InvalidOperation -> Argument Exceptions
Banane9 cc45c1d
Fix GenericParameter checks
Banane9 01e0285
Make TypeDefinition public
Banane9 a43c25a
It's documentin time (for generic method invokers)
Banane9 9177bc4
Merge branch 'master' into master
zkxs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Reflection; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace NeosModLoader.Utility | ||
| { | ||
| /// <summary> | ||
| /// Represents the base class for more specific generic method invokers. | ||
| /// </summary> | ||
| /// <typeparam name="TInstance">The type of the instances that the generic method gets invoked on.</typeparam> | ||
| /// <typeparam name="TReturn">The type of the generic method's return value. Use <c>object</c> if it depends on the generic type parameters of the method.</typeparam> | ||
| public abstract class BaseGenericMethodInvoker<TInstance, TReturn> | ||
| { | ||
| private readonly Dictionary<TypeDefinition, MethodInfo> concreteMethods = new(); | ||
|
|
||
| /// <summary> | ||
| /// Gets the generic <see cref="MethodInfo"/> who's concrete versions will be in invoked by this generic method invoker. | ||
| /// </summary> | ||
| public MethodInfo GenericMethod { get; } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new generic method invoker for the given method which may not have generic type parameters. | ||
| /// <para/> | ||
| /// Use <c>object</c> for <typeparamref name="TReturn"/> if it depends on the generic type parameters of the method. | ||
| /// </summary> | ||
| /// <param name="method">The generic method to invoke concrete version of.</param> | ||
| /// <param name="ignoreLackOfGenericParameters">Ignores the method lacking generic type parameters if <c>true</c>.</param> | ||
| internal BaseGenericMethodInvoker(MethodInfo method, bool ignoreLackOfGenericParameters) | ||
| { | ||
| if (!ignoreLackOfGenericParameters && !method.ContainsGenericParameters) | ||
| throw new ArgumentException("Target method must have remaining open type parameters.", nameof(method)); | ||
|
|
||
| GenericMethod = method; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new generic method invoker for the given open generic method. | ||
| /// <para/> | ||
| /// Use <c>object</c> for <typeparamref name="TReturn"/> if it depends on the generic type parameters of the method. | ||
| /// </summary> | ||
| /// <param name="method">The generic method to invoke concrete version of.</param> | ||
| internal BaseGenericMethodInvoker(MethodInfo method) : this(method, false) | ||
| { } | ||
|
|
||
| /// <summary> | ||
| /// Invokes a concrete version of this invoker's <see cref="GenericMethod">GenericMethod</see> using the given <paramref name="instance"/>, | ||
| /// type parameter <paramref name="definition"/> and method <paramref name="parameters"/>. | ||
| /// </summary> | ||
| /// <param name="instance">The object instance to invoke the method on. Use <c>null</c> for static methods.</param> | ||
| /// <param name="definition">The generic type parameter definition to create the concrete method with.<br/> | ||
| /// May be ignored if <see cref="GenericMethod"/> doesn't contain generic parameters.</param> | ||
| /// <param name="parameters">The parameters to invoke the method with. May be empty or null if there is none.</param> | ||
| /// <returns>The result of the method invocation.</returns> | ||
| internal TReturn InvokeInternal(TInstance? instance, TypeDefinition definition, params object[]? parameters) | ||
| { | ||
| if (!concreteMethods.TryGetValue(definition, out var method)) | ||
| { | ||
| if (GenericMethod.ContainsGenericParameters) | ||
| method = GenericMethod.MakeGenericMethod(definition.types); | ||
| else | ||
| method = GenericMethod; | ||
|
|
||
| concreteMethods.Add(definition, method); | ||
| } | ||
|
|
||
| return (TReturn)method.Invoke(instance, parameters); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Represents a generic method invoker that invokes instance methods with a return value. | ||
| /// </summary> | ||
| /// <inheritdoc/> | ||
| public sealed class GenericInstanceMethodInvoker<TInstance, TReturn> : BaseGenericMethodInvoker<TInstance, TReturn> | ||
| { | ||
| /// <summary> | ||
| /// Creates a new generic method invoker for the given open generic instance method with a return value. | ||
| /// <para/> | ||
| /// Use <c>object</c> for <typeparamref name="TReturn"/> if it depends on the generic type parameters of the method. | ||
| /// </summary> | ||
| /// <param name="method">The generic method to invoke concrete version of.</param> | ||
| public GenericInstanceMethodInvoker(MethodInfo method) : base(method) | ||
| { } | ||
|
|
||
| internal GenericInstanceMethodInvoker(MethodInfo method, bool ignoreLackOfGenericParameters) | ||
| : base(method, ignoreLackOfGenericParameters) | ||
| { } | ||
|
|
||
| /// <summary> | ||
| /// Invokes a concrete version of this invoker's | ||
| /// <see cref="BaseGenericMethodInvoker{TInstance, TReturn}.GenericMethod">GenericMethod</see> | ||
| /// using the given <paramref name="instance"/>, type parameter <paramref name="definition"/> and method <paramref name="parameters"/>. | ||
| /// </summary> | ||
| /// <param name="instance">The object instance to invoke the method on.</param> | ||
| /// <param name="definition">The generic type parameter definition to create the concrete method with.</param> | ||
| /// <param name="parameters">The parameters to invoke the method with.</param> | ||
| /// <returns>The result of the method invocation.</returns> | ||
| public TReturn Invoke(TInstance instance, TypeDefinition definition, params object[] parameters) | ||
| { | ||
| return InvokeInternal(instance, definition, parameters); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Represents a generic method invoker that invokes static methods with a return value. | ||
| /// </summary> | ||
| /// <inheritdoc/> | ||
| public sealed class GenericStaticMethodInvoker<TReturn> : BaseGenericMethodInvoker<object, TReturn> | ||
| { | ||
| /// <summary> | ||
| /// Creates a new generic method invoker for the given open generic static method with a return value. | ||
| /// <para/> | ||
| /// Use <c>object</c> for <typeparamref name="TReturn"/> if it depends on the generic type parameters of the method. | ||
| /// </summary> | ||
| /// <param name="method">The generic method to invoke concrete version of.</param> | ||
| public GenericStaticMethodInvoker(MethodInfo method) : base(method) | ||
| { } | ||
|
|
||
| /// <summary> | ||
| /// Invokes a concrete version of this invoker's static | ||
| /// <see cref="BaseGenericMethodInvoker{TInstance, TReturn}.GenericMethod">GenericMethod</see> | ||
| /// using the given type parameter <paramref name="definition"/> and method <paramref name="parameters"/>. | ||
| /// </summary> | ||
| /// <param name="definition">The generic type parameter definition to create the concrete method with.</param> | ||
| /// <param name="parameters">The parameters to invoke the method with.</param> | ||
| /// <returns>The result of the method invocation.</returns> | ||
| public TReturn Invoke(TypeDefinition definition, params object[] parameters) | ||
| { | ||
| return InvokeInternal(null, definition, parameters); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Represents a generic method invoker that invokes static void methods. | ||
| /// </summary> | ||
| public sealed class GenericStaticVoidMethodInvoker : BaseGenericMethodInvoker<object, object> | ||
| { | ||
| /// <summary> | ||
| /// Creates a new generic method invoker for the given open generic static void method. | ||
| /// </summary> | ||
| /// <param name="method">The generic method to invoke concrete version of.</param> | ||
| public GenericStaticVoidMethodInvoker(MethodInfo method) : base(method) | ||
| { } | ||
|
|
||
| /// <summary> | ||
| /// Invokes a concrete version of this invoker's static void | ||
| /// <see cref="BaseGenericMethodInvoker{TInstance, TReturn}.GenericMethod">GenericMethod</see> | ||
| /// using the given type parameter <paramref name="definition"/> and method <paramref name="parameters"/>. | ||
| /// </summary> | ||
| /// <param name="definition">The generic type parameter definition to create the concrete method with.</param> | ||
| /// <param name="parameters">The parameters to invoke the method with.</param> | ||
| /// <returns>The result of the method invocation.</returns> | ||
| public void Invoke(TypeDefinition definition, params object[] parameters) | ||
| { | ||
| InvokeInternal(null, definition, parameters); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Represents a generic method invoker that invokes instance void methods. | ||
| /// </summary> | ||
| /// <inheritdoc/> | ||
| public sealed class GenericVoidMethodInvoker<TInstance> : BaseGenericMethodInvoker<TInstance, object> | ||
| { | ||
| /// <summary> | ||
| /// Creates a new generic method invoker for the given open generic instance void method. | ||
| /// </summary> | ||
| /// <param name="method">The generic method to invoke concrete version of.</param> | ||
| public GenericVoidMethodInvoker(MethodInfo method) : base(method) | ||
| { } | ||
|
|
||
| /// <summary> | ||
| /// Invokes a concrete version of this invoker's void | ||
| /// <see cref="BaseGenericMethodInvoker{TInstance, TReturn}.GenericMethod">GenericMethod</see> | ||
| /// using the given <paramref name="instance"/>, type parameter <paramref name="definition"/> and method <paramref name="parameters"/>. | ||
| /// </summary> | ||
| /// <param name="instance">The object instance to invoke the method on.</param> | ||
| /// <param name="definition">The generic type parameter definition to create the concrete method with.</param> | ||
| /// <param name="parameters">The parameters to invoke the method with.</param> | ||
| public void Invoke(TInstance instance, TypeDefinition definition, params object[] parameters) | ||
| { | ||
| InvokeInternal(instance, definition, parameters); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.