Implement constructors & methods on constructed generics.
We adopt roughly the same approach as the C# Reflection API: a GenericMethodDefinition is a method which has no method parameters substituted, but lives in a open or closed type with some or all type parameters substituted. To ensure the uniqueness of the MethodInfo, we cache by the method type arguments, and also cache generated DeclaredConstructors/DeclaredMethods in the TypeInfo. This also enables MakeGenericMethod, albeit in a slightly different form than the Reflection API: MakeGenericMethod lives in MethodBase, so it's callable from a constructor (even though in C# constructors cannot be generic). This slight violation of the spec reduces code duplication, so it's probably worth it. Finally, VirtualAddress gets set when populating GenericMethods, and so it'll work whether or not the methods get cached/generated ahead of time.
This commit is contained in:
@@ -20,7 +20,11 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
public ConstructorInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) { }
|
public ConstructorInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) { }
|
||||||
|
|
||||||
public ConstructorInfo(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(model, spec, declaringType) { }
|
public ConstructorInfo(ConstructorInfo methodDef, TypeInfo declaringType) : base(methodDef, declaringType) { }
|
||||||
|
|
||||||
|
private ConstructorInfo(ConstructorInfo methodDef, TypeInfo[] typeArguments) : base(methodDef, typeArguments) { }
|
||||||
|
|
||||||
|
protected override MethodBase MakeGenericMethodImpl(TypeInfo[] typeArguments) => new ConstructorInfo(this, typeArguments);
|
||||||
|
|
||||||
public override string ToString() => DeclaringType.Name + GetFullTypeParametersString()
|
public override string ToString() => DeclaringType.Name + GetFullTypeParametersString()
|
||||||
+ "(" + string.Join(", ", DeclaredParameters.Select(x => x.ParameterType.Name)) + ")";
|
+ "(" + string.Join(", ", DeclaredParameters.Select(x => x.ParameterType.Name)) + ")";
|
||||||
|
|||||||
@@ -98,11 +98,19 @@ namespace Il2CppInspector.Reflection
|
|||||||
declaringType = declaringType.MakeGenericType(genericArguments);
|
declaringType = declaringType.MakeGenericType(genericArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concrete instance of a generic method
|
MethodBase method;
|
||||||
if (methodDefinition is MethodInfo)
|
if (methodDefinition is ConstructorInfo)
|
||||||
GenericMethods[spec] = new MethodInfo(this, spec, declaringType);
|
method = declaringType.GetConstructorByDefinition((ConstructorInfo)methodDefinition);
|
||||||
else
|
else
|
||||||
GenericMethods[spec] = new ConstructorInfo(this, spec, declaringType);
|
method = declaringType.GetMethodByDefinition((MethodInfo)methodDefinition);
|
||||||
|
|
||||||
|
if (spec.methodIndexIndex != -1) {
|
||||||
|
var genericInstance = Package.GenericInstances[spec.methodIndexIndex];
|
||||||
|
var genericArguments = ResolveGenericArguments(genericInstance);
|
||||||
|
method = method.MakeGenericMethod(genericArguments);
|
||||||
|
}
|
||||||
|
method.VirtualAddress = Package.GetGenericMethodPointer(spec);
|
||||||
|
GenericMethods[spec] = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all custom attribute generators (populate AttributesByIndices) (use ToList() to force evaluation)
|
// Find all custom attribute generators (populate AttributesByIndices) (use ToList() to force evaluation)
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ namespace Il2CppInspector.Reflection
|
|||||||
// IL2CPP-specific data
|
// IL2CPP-specific data
|
||||||
public Il2CppMethodDefinition Definition { get; }
|
public Il2CppMethodDefinition Definition { get; }
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
public (ulong Start, ulong End)? VirtualAddress { get; }
|
public (ulong Start, ulong End)? VirtualAddress { get; set; }
|
||||||
|
// This dictionary will cache all instantiated generic methods.
|
||||||
|
// Only valid for GenericMethodDefinition - not valid on instantiated types!
|
||||||
|
private Dictionary<TypeInfo[], MethodBase> genericMethodInstances;
|
||||||
|
|
||||||
|
// Root method definition: the method with Definition != null
|
||||||
|
protected readonly MethodBase rootDefinition;
|
||||||
|
|
||||||
// Method.Invoke implementation
|
// Method.Invoke implementation
|
||||||
public MethodInvoker Invoker { get; set; }
|
public MethodInvoker Invoker { get; set; }
|
||||||
@@ -26,7 +32,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
public MethodAttributes Attributes { get; protected set; }
|
public MethodAttributes Attributes { get; protected set; }
|
||||||
|
|
||||||
// Custom attributes for this member
|
// Custom attributes for this member
|
||||||
public override IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(this);
|
public override IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(rootDefinition);
|
||||||
|
|
||||||
public List<ParameterInfo> DeclaredParameters { get; } = new List<ParameterInfo>();
|
public List<ParameterInfo> DeclaredParameters { get; } = new List<ParameterInfo>();
|
||||||
|
|
||||||
@@ -46,7 +52,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
public virtual bool RequiresUnsafeContext => DeclaredParameters.Any(p => p.ParameterType.RequiresUnsafeContext);
|
public virtual bool RequiresUnsafeContext => DeclaredParameters.Any(p => p.ParameterType.RequiresUnsafeContext);
|
||||||
|
|
||||||
// True if the method contains unresolved generic type parameters, or if it is a non-generic method in an open ganeric type
|
// True if the method contains unresolved generic type parameters, or if it is a non-generic method in an open generic type
|
||||||
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.containsgenericparameters?view=netframework-4.8
|
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.containsgenericparameters?view=netframework-4.8
|
||||||
public bool ContainsGenericParameters => DeclaringType.ContainsGenericParameters || genericArguments.Any(ga => ga.ContainsGenericParameters);
|
public bool ContainsGenericParameters => DeclaringType.ContainsGenericParameters || genericArguments.Any(ga => ga.ContainsGenericParameters);
|
||||||
|
|
||||||
@@ -61,9 +67,19 @@ namespace Il2CppInspector.Reflection
|
|||||||
// This was added in .NET Core 2.1 and isn't properly documented yet
|
// This was added in .NET Core 2.1 and isn't properly documented yet
|
||||||
public bool IsConstructedGenericMethod => IsGenericMethod && !IsGenericMethodDefinition;
|
public bool IsConstructedGenericMethod => IsGenericMethod && !IsGenericMethodDefinition;
|
||||||
|
|
||||||
|
// Generic method definition: either a method with Definition != null, or an open method of a generic type
|
||||||
|
private readonly MethodBase genericMethodDefinition;
|
||||||
|
public MethodBase GetGenericMethodDefinition() {
|
||||||
|
if (genericMethodDefinition != null)
|
||||||
|
return genericMethodDefinition;
|
||||||
|
if (genericArguments.Any())
|
||||||
|
return this;
|
||||||
|
throw new InvalidOperationException("This method can only be called on generic methods");
|
||||||
|
}
|
||||||
|
|
||||||
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.isgenericmethod?view=netframework-4.8
|
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.isgenericmethod?view=netframework-4.8
|
||||||
public bool IsGenericMethod { get; }
|
public bool IsGenericMethod { get; }
|
||||||
public bool IsGenericMethodDefinition => (Definition != null) && genericArguments.Any();
|
public bool IsGenericMethodDefinition => (genericMethodDefinition == null) && genericArguments.Any();
|
||||||
|
|
||||||
// TODO: GetMethodBody()
|
// TODO: GetMethodBody()
|
||||||
|
|
||||||
@@ -98,6 +114,8 @@ namespace Il2CppInspector.Reflection
|
|||||||
// Add to global method definition list
|
// Add to global method definition list
|
||||||
Assembly.Model.MethodsByDefinitionIndex[Index] = this;
|
Assembly.Model.MethodsByDefinitionIndex[Index] = this;
|
||||||
|
|
||||||
|
rootDefinition = this;
|
||||||
|
|
||||||
// Generic method definition?
|
// Generic method definition?
|
||||||
if (Definition.genericContainerIndex >= 0) {
|
if (Definition.genericContainerIndex >= 0) {
|
||||||
IsGenericMethod = true;
|
IsGenericMethod = true;
|
||||||
@@ -106,6 +124,8 @@ namespace Il2CppInspector.Reflection
|
|||||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||||
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
||||||
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||||
|
genericMethodInstances = new Dictionary<TypeInfo[], MethodBase>(new TypeInfo.TypeArgumentsComparer());
|
||||||
|
genericMethodInstances[genericArguments] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set method attributes
|
// Set method attributes
|
||||||
@@ -145,30 +165,64 @@ namespace Il2CppInspector.Reflection
|
|||||||
DeclaredParameters.Add(new ParameterInfo(pkg, p, this));
|
DeclaredParameters.Add(new ParameterInfo(pkg, p, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a method from a concrete generic method (MethodSpec)
|
protected MethodBase(MethodBase methodDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
protected MethodBase(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(declaringType) {
|
if (methodDef.Definition == null)
|
||||||
var methodDef = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex];
|
throw new ArgumentException("Argument must be a bare method definition");
|
||||||
|
|
||||||
|
rootDefinition = methodDef;
|
||||||
Name = methodDef.Name;
|
Name = methodDef.Name;
|
||||||
Attributes = methodDef.Attributes;
|
Attributes = methodDef.Attributes;
|
||||||
|
VirtualAddress = methodDef.VirtualAddress;
|
||||||
|
|
||||||
if (spec.methodIndexIndex >= 0) {
|
|
||||||
IsGenericMethod = true;
|
|
||||||
genericArguments = model.ResolveGenericArguments(model.Package.GenericInstances[spec.methodIndexIndex]);
|
|
||||||
} else {
|
|
||||||
IsGenericMethod = methodDef.IsGenericMethod;
|
IsGenericMethod = methodDef.IsGenericMethod;
|
||||||
genericArguments = methodDef.GetGenericArguments();
|
genericArguments = methodDef.GetGenericArguments();
|
||||||
}
|
|
||||||
var genericTypeArguments = declaringType.GetGenericArguments();
|
var genericTypeArguments = declaringType.GetGenericArguments();
|
||||||
|
|
||||||
// Substitute matching generic type parameters with concrete type arguments
|
genericMethodInstances = new Dictionary<TypeInfo[], MethodBase>(new TypeInfo.TypeArgumentsComparer());
|
||||||
DeclaredParameters = methodDef.DeclaredParameters
|
genericMethodInstances[genericArguments] = this;
|
||||||
.Select(p => p.SubstituteGenericArguments(genericTypeArguments, genericArguments))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
VirtualAddress = model.Package.GetGenericMethodPointer(spec);
|
DeclaredParameters = rootDefinition.DeclaredParameters
|
||||||
|
.Select(p => p.SubstituteGenericArguments(this, genericTypeArguments, genericArguments))
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected MethodBase(MethodBase methodDef, TypeInfo[] typeArguments) : base(methodDef.DeclaringType) {
|
||||||
|
if (!methodDef.IsGenericMethodDefinition)
|
||||||
|
throw new InvalidOperationException(methodDef.Name + " is not a generic method definition.");
|
||||||
|
|
||||||
|
rootDefinition = methodDef.rootDefinition;
|
||||||
|
genericMethodDefinition = methodDef;
|
||||||
|
Name = methodDef.Name;
|
||||||
|
Attributes = methodDef.Attributes;
|
||||||
|
VirtualAddress = methodDef.VirtualAddress;
|
||||||
|
|
||||||
|
IsGenericMethod = true;
|
||||||
|
genericArguments = typeArguments;
|
||||||
|
var genericTypeArguments = DeclaringType.GetGenericArguments();
|
||||||
|
|
||||||
|
DeclaredParameters = rootDefinition.DeclaredParameters
|
||||||
|
.Select(p => p.SubstituteGenericArguments(this, genericTypeArguments, genericArguments))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strictly speaking, this should live in MethodInfo; constructors cannot have generic arguments.
|
||||||
|
// However, Il2Cpp unifies Constructor and Method to a much greater extent, so that's why this is
|
||||||
|
// here instead.
|
||||||
|
public MethodBase MakeGenericMethod(params TypeInfo[] typeArguments) {
|
||||||
|
if (typeArguments.Length != genericArguments.Length) {
|
||||||
|
throw new ArgumentException("The number of generic arguments provided does not match the generic type definition.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodBase result;
|
||||||
|
if (genericMethodInstances.TryGetValue(typeArguments, out result))
|
||||||
|
return result;
|
||||||
|
result = MakeGenericMethodImpl(typeArguments);
|
||||||
|
genericMethodInstances[typeArguments] = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract MethodBase MakeGenericMethodImpl(TypeInfo[] typeArguments);
|
||||||
|
|
||||||
public string GetAccessModifierString() => this switch {
|
public string GetAccessModifierString() => this switch {
|
||||||
// Static constructors can not have an access level modifier
|
// Static constructors can not have an access level modifier
|
||||||
{ IsConstructor: true, IsStatic: true } => "",
|
{ IsConstructor: true, IsStatic: true } => "",
|
||||||
|
|||||||
@@ -28,11 +28,18 @@ namespace Il2CppInspector.Reflection
|
|||||||
ReturnParameter = new ParameterInfo(pkg, -1, this);
|
ReturnParameter = new ParameterInfo(pkg, -1, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodInfo(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(model, spec, declaringType) {
|
public MethodInfo(MethodInfo methodDef, TypeInfo declaringType) : base(methodDef, declaringType) {
|
||||||
var methodDef = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex];
|
ReturnParameter = ((MethodInfo)rootDefinition).ReturnParameter
|
||||||
ReturnParameter = ((MethodInfo)methodDef).ReturnParameter.SubstituteGenericArguments(declaringType.GetGenericArguments(), GetGenericArguments());
|
.SubstituteGenericArguments(this, DeclaringType.GetGenericArguments(), GetGenericArguments());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MethodInfo(MethodInfo methodDef, TypeInfo[] typeArguments) : base(methodDef, typeArguments) {
|
||||||
|
ReturnParameter = ((MethodInfo)rootDefinition).ReturnParameter
|
||||||
|
.SubstituteGenericArguments(this, DeclaringType.GetGenericArguments(), GetGenericArguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override MethodBase MakeGenericMethodImpl(TypeInfo[] typeArguments) => new MethodInfo(this, typeArguments);
|
||||||
|
|
||||||
public override string ToString() => ReturnType.Name + " " + Name + GetFullTypeParametersString() + "(" + string.Join(", ",
|
public override string ToString() => ReturnType.Name + " " + Name + GetFullTypeParametersString() + "(" + string.Join(", ",
|
||||||
DeclaredParameters.Select(x => x.ParameterType.IsByRef? x.ParameterType.Name.TrimEnd('&') + " ByRef" : x.ParameterType.Name)) + ")";
|
DeclaredParameters.Select(x => x.ParameterType.IsByRef? x.ParameterType.Name.TrimEnd('&') + " ByRef" : x.ParameterType.Name)) + ")";
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,14 @@ namespace Il2CppInspector.Reflection
|
|||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
public ulong DefaultValueMetadataAddress { get; }
|
public ulong DefaultValueMetadataAddress { get; }
|
||||||
|
|
||||||
|
// Root definition: the parameter with Definition != null
|
||||||
|
private readonly ParameterInfo rootDefinition;
|
||||||
|
|
||||||
// Information/flags about the parameter
|
// Information/flags about the parameter
|
||||||
public ParameterAttributes Attributes { get; }
|
public ParameterAttributes Attributes { get; }
|
||||||
|
|
||||||
// Custom attributes for this parameter
|
// Custom attributes for this parameter
|
||||||
public IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(this);
|
public IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(rootDefinition);
|
||||||
|
|
||||||
// True if the parameter has a default value
|
// True if the parameter has a default value
|
||||||
public bool HasDefaultValue => (Attributes & ParameterAttributes.HasDefault) != 0;
|
public bool HasDefaultValue => (Attributes & ParameterAttributes.HasDefault) != 0;
|
||||||
@@ -63,6 +66,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
Definition = pkg.Params[Index];
|
Definition = pkg.Params[Index];
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.nameIndex];
|
||||||
|
rootDefinition = this;
|
||||||
|
|
||||||
// Handle unnamed/obfuscated parameter names
|
// Handle unnamed/obfuscated parameter names
|
||||||
if (string.IsNullOrEmpty(Name))
|
if (string.IsNullOrEmpty(Name))
|
||||||
@@ -97,9 +101,10 @@ namespace Il2CppInspector.Reflection
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a concrete type parameter from a generic type parameter
|
// Create a concrete type parameter from a generic type parameter
|
||||||
public ParameterInfo(ParameterInfo generic, TypeInfo concrete) {
|
private ParameterInfo(ParameterInfo generic, MethodBase declaringMethod, TypeInfo concrete) {
|
||||||
|
rootDefinition = generic.rootDefinition;
|
||||||
|
|
||||||
DeclaringMethod = generic.DeclaringMethod;
|
DeclaringMethod = declaringMethod;
|
||||||
Name = generic.Name;
|
Name = generic.Name;
|
||||||
Position = generic.Position;
|
Position = generic.Position;
|
||||||
Attributes = generic.Attributes;
|
Attributes = generic.Attributes;
|
||||||
@@ -110,11 +115,11 @@ namespace Il2CppInspector.Reflection
|
|||||||
DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress;
|
DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParameterInfo SubstituteGenericArguments(TypeInfo[] typeArguments, TypeInfo[] methodArguments = null) {
|
public ParameterInfo SubstituteGenericArguments(MethodBase declaringMethod, TypeInfo[] typeArguments, TypeInfo[] methodArguments = null) {
|
||||||
TypeInfo t = ParameterType.SubstituteGenericArguments(typeArguments, methodArguments);
|
TypeInfo t = ParameterType.SubstituteGenericArguments(typeArguments, methodArguments);
|
||||||
if (t == ParameterType)
|
if (t == ParameterType)
|
||||||
return this;
|
return this;
|
||||||
return new ParameterInfo(this, t);
|
return new ParameterInfo(this, declaringMethod, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ref will be handled as part of the type name
|
// ref will be handled as part of the type name
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -21,7 +22,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// This dictionary will cache all instantiated generic types out of this definition.
|
// This dictionary will cache all instantiated generic types out of this definition.
|
||||||
// Only valid for GenericTypeDefinition - not valid on instantiated types!
|
// Only valid for GenericTypeDefinition - not valid on instantiated types!
|
||||||
private Dictionary<TypeInfo[], TypeInfo> genericTypeInstances;
|
private Dictionary<TypeInfo[], TypeInfo> genericTypeInstances;
|
||||||
private class TypeArgumentsComparer : EqualityComparer<TypeInfo[]>
|
public class TypeArgumentsComparer : EqualityComparer<TypeInfo[]>
|
||||||
{
|
{
|
||||||
public override bool Equals(TypeInfo[] x, TypeInfo[] y) {
|
public override bool Equals(TypeInfo[] x, TypeInfo[] y) {
|
||||||
return ((IStructuralEquatable)x).Equals(y, StructuralComparisons.StructuralEqualityComparer);
|
return ((IStructuralEquatable)x).Equals(y, StructuralComparisons.StructuralEqualityComparer);
|
||||||
@@ -94,7 +95,20 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// Custom attributes for this member
|
// Custom attributes for this member
|
||||||
public override IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(genericTypeDefinition ?? this);
|
public override IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(genericTypeDefinition ?? this);
|
||||||
|
|
||||||
public List<ConstructorInfo> DeclaredConstructors { get; } = new List<ConstructorInfo>();
|
private List<ConstructorInfo> declaredConstructors;
|
||||||
|
public ReadOnlyCollection<ConstructorInfo> DeclaredConstructors {
|
||||||
|
get {
|
||||||
|
if (declaredConstructors != null)
|
||||||
|
return declaredConstructors.AsReadOnly();
|
||||||
|
if(genericTypeDefinition != null) {
|
||||||
|
var result = genericTypeDefinition.DeclaredConstructors.Select(c => new ConstructorInfo(c, this)).ToList();
|
||||||
|
declaredConstructors = result;
|
||||||
|
return result.AsReadOnly();
|
||||||
|
}
|
||||||
|
return new List<ConstructorInfo>().AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<EventInfo> DeclaredEvents { get; } = new List<EventInfo>();
|
public List<EventInfo> DeclaredEvents { get; } = new List<EventInfo>();
|
||||||
public List<FieldInfo> DeclaredFields { get; } = new List<FieldInfo>();
|
public List<FieldInfo> DeclaredFields { get; } = new List<FieldInfo>();
|
||||||
|
|
||||||
@@ -103,7 +117,19 @@ namespace Il2CppInspector.Reflection {
|
|||||||
DeclaredNestedTypes, DeclaredProperties
|
DeclaredNestedTypes, DeclaredProperties
|
||||||
}.SelectMany(m => m).ToList();
|
}.SelectMany(m => m).ToList();
|
||||||
|
|
||||||
public List<MethodInfo> DeclaredMethods { get; } = new List<MethodInfo>();
|
private List<MethodInfo> declaredMethods;
|
||||||
|
public ReadOnlyCollection<MethodInfo> DeclaredMethods {
|
||||||
|
get {
|
||||||
|
if (declaredMethods != null)
|
||||||
|
return declaredMethods.AsReadOnly();
|
||||||
|
if (genericTypeDefinition != null) {
|
||||||
|
var result = genericTypeDefinition.DeclaredMethods.Select(c => new MethodInfo(c, this)).ToList();
|
||||||
|
declaredMethods = result;
|
||||||
|
return result.AsReadOnly();
|
||||||
|
}
|
||||||
|
return new List<MethodInfo>().AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly TypeRef[] declaredNestedTypes;
|
private readonly TypeRef[] declaredNestedTypes;
|
||||||
public IEnumerable<TypeInfo> DeclaredNestedTypes {
|
public IEnumerable<TypeInfo> DeclaredNestedTypes {
|
||||||
@@ -142,6 +168,29 @@ namespace Il2CppInspector.Reflection {
|
|||||||
throw new InvalidOperationException("This method can only be called on generic types");
|
throw new InvalidOperationException("This method can only be called on generic types");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConstructorInfo GetConstructorByDefinition(ConstructorInfo definition) {
|
||||||
|
if (genericTypeDefinition != null) {
|
||||||
|
var collection = genericTypeDefinition.DeclaredConstructors;
|
||||||
|
for (int i = 0; i < collection.Count; i++) {
|
||||||
|
if (collection[i] == definition)
|
||||||
|
return DeclaredConstructors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a method or constructor by the base type definition of that method
|
||||||
|
public MethodInfo GetMethodByDefinition(MethodInfo definition) {
|
||||||
|
if (genericTypeDefinition != null) {
|
||||||
|
var collection = genericTypeDefinition.DeclaredMethods;
|
||||||
|
for (int i = 0; i < collection.Count; i++) {
|
||||||
|
if (collection[i] == definition)
|
||||||
|
return DeclaredMethods[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
// Get a method by its name
|
// Get a method by its name
|
||||||
public MethodInfo GetMethod(string name) => DeclaredMethods.FirstOrDefault(m => m.Name == name);
|
public MethodInfo GetMethod(string name) => DeclaredMethods.FirstOrDefault(m => m.Name == name);
|
||||||
|
|
||||||
@@ -692,12 +741,14 @@ namespace Il2CppInspector.Reflection {
|
|||||||
DeclaredFields.Add(new FieldInfo(pkg, f, this));
|
DeclaredFields.Add(new FieldInfo(pkg, f, this));
|
||||||
|
|
||||||
// Add all methods
|
// Add all methods
|
||||||
|
declaredConstructors = new List<ConstructorInfo>();
|
||||||
|
declaredMethods = new List<MethodInfo>();
|
||||||
for (var m = Definition.methodStart; m < Definition.methodStart + Definition.method_count; m++) {
|
for (var m = Definition.methodStart; m < Definition.methodStart + Definition.method_count; m++) {
|
||||||
var method = new MethodInfo(pkg, m, this);
|
var method = new MethodInfo(pkg, m, this);
|
||||||
if (method.Name == ConstructorInfo.ConstructorName || method.Name == ConstructorInfo.TypeConstructorName)
|
if (method.Name == ConstructorInfo.ConstructorName || method.Name == ConstructorInfo.TypeConstructorName)
|
||||||
DeclaredConstructors.Add(new ConstructorInfo(pkg, m, this));
|
declaredConstructors.Add(new ConstructorInfo(pkg, m, this));
|
||||||
else
|
else
|
||||||
DeclaredMethods.Add(method);
|
declaredMethods.Add(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all properties
|
// Add all properties
|
||||||
@@ -776,7 +827,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// and returns a TypeInfo object representing the resulting constructed type.
|
// and returns a TypeInfo object representing the resulting constructed type.
|
||||||
// See: https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype?view=netframework-4.8
|
// See: https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype?view=netframework-4.8
|
||||||
public TypeInfo MakeGenericType(params TypeInfo[] typeArguments) {
|
public TypeInfo MakeGenericType(params TypeInfo[] typeArguments) {
|
||||||
if(typeArguments.Length != genericArguments.Length) {
|
if (typeArguments.Length != genericArguments.Length) {
|
||||||
throw new ArgumentException("The number of generic arguments provided does not match the generic type definition.");
|
throw new ArgumentException("The number of generic arguments provided does not match the generic type definition.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user