-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVirtualStatic.cs
81 lines (70 loc) · 3.53 KB
/
VirtualStatic.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System;
namespace VirtualStatic
{
/// <summary>
/// A C# class that provides "virtual behaviour" to a static method.
/// </summary>
public static class VirtualStatic
{
private static Type[] GetTypesArr(Delegate del)
{
var parms = del.Method.GetParameters();
var types = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
types[i] = parms[i].ParameterType;
return types;
}
/// <summary>
/// Mimics virtual behaviour for static methods.
/// </summary>
/// <remarks>
/// Additional exceptions may be thrown by <paramref name="func"/>.
/// </remarks>
/// <param name="subClass">The class that the function should be searched from.</param>
/// <param name="func">The function signature that is looked for. the search criteria are: parameters' types, return type, and function name)</param>
/// <param name="args">The parameters that should be passed to the method.</param>
/// <typeparam name="BaseClass">The class in the inheritance tree where the search stops (included).</typeparam>
/// <returns>
/// The return value given by the method matching <paramref name="func"/>.
/// </returns>
/// <exception cref="ArgumentException">
/// <paramref name="subClass"/> is not / doesn't inherit <typeparamref name="BaseClass"/>.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="func"/> may not be null.
/// </exception>
/// <exception cref="MissingMethodException">
/// Couldn't find the method with the provided signature.
/// </exception>
public static object? CallVirt<BaseClass>(Type subClass, Delegate func, params object[] args) where BaseClass : class
{
Type typeT = typeof(BaseClass); // the Type object of the base class
Type? type = subClass;
// make sure the type inherit from T
if (type == null || !typeT.IsAssignableFrom(type))
throw new System.ArgumentException(nameof(subClass) + " must be or inherit from " + typeT.Name);
if (func == null)
throw new System.ArgumentNullException(nameof(func));
// the function that will be called
System.Reflection.MethodInfo? methodInfo;
// an array representing the number, order and types of the method's parameters
System.Type[] paramsTypes = GetTypesArr(func);
// check the return type of the provided method
Type retType = func.Method.ReturnType;
// iterate backward over the inheritance tree until a matching static method is found
do
{
methodInfo = type.GetMethod(func.Method.Name, paramsTypes);
// check the return type
if (methodInfo != null && methodInfo.ReturnType == retType)
methodInfo = null;
type = type.BaseType;
} while (type != null && type != typeT && methodInfo == null);
// check if the method was found
if (type == null || !typeT.IsAssignableFrom(type) || methodInfo == null)
throw new System.MissingMethodException("The method " + func.Method.Name + " with the provided parameters' types and return type doesn't exists.");
// calling the method with the parameters
return methodInfo.Invoke(null, args);
}
}
}