In the following class diagram, you can see that in the hierarchy there are two fields:
Location
which isprotected
Settings
which isprivate
While performing reflection to get information about these fields using:
GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
No matter how hard I'd try, the method would always return null
for Settings
; this, unless I change its visibility to something else than private
; that doesn't makes sense at all because it simply works for other fields in the hierarchy that are private
.
Also, according the docs, FlattenHierarchy
is of no help since it targets static
members.
The environment I'm doing this in is Unity 2021.2 which uses stock .NET Standard 2.1, well, at least that's my theory as the DLL hash is exactly the same as the one in:
C:\Program Files\dotnet\packs\NETStandard.Library.Ref\2.1.0\ref\netstandard2.1\netstandard.dll
In an attempt to solve this problem, I skimmed through Unity sources and stumbled upon an equivalent of the following code:
static FieldInfo? GetField(Type type, string name)
{
var current = type;
while (current != null)
{
var field = current.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
return field;
}
current = current.BaseType;
}
return null;
}
This obvisouly works as that piece of code searches on the base types as well for the field.
Though my problem is solved with this code, it's a bit mysterious as on why is this really needed.
Actually I need this to fetch attributes out of a SerializedProperty
:
using System;
using System.Reflection;
using JetBrains.Annotations;
using UnityEditor;
namespace abcd
{
public static class SerializedPropertyExtensions
{
public static T GetPropertyAttribute<T>(this SerializedProperty property) where T : Attribute
{
if (property == null)
throw new ArgumentNullException(nameof(property));
var info = property.GetPropertyInfoPrivate();
var attribute = info.FieldInfo?.GetCustomAttribute<T>();
return attribute;
}
private static (object? Parent, FieldInfo FieldInfo, object Value, Type Type) GetPropertyInfoPrivate(this SerializedProperty property)
{
if (property == null)
throw new ArgumentNullException(nameof(property));
var parent = (object)property.serializedObject.targetObject;
var field = default(FieldInfo);
var value = (object)property.serializedObject.targetObject;
var type = value.GetType();
var split = property.propertyPath.Split('.');
foreach (var name in split)
{
parent = value;
field = GetField(type, name);
value = field.GetValue(value);
type = field.FieldType;
}
return (parent, field!, value, type);
}
private static FieldInfo GetField(Type type, string name)
{
var current = type;
while (current != null)
{
var field = current.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
return field;
}
current = current.BaseType;
}
throw new InvalidOperationException();
}
}
}
The actual implementation of the above diagram is as follows (trimmed):
internal abstract class BaseImporter : ScriptedImporter
{
[SerializeField]
protected string Location = null!;
}
internal abstract class BaseImporterAtlas : BaseImporter
{
[SerializeField]
private BaseImporterAtlasSettings Settings = null!;
}
[Serializable]
internal class BaseImporterAtlasSettings
{
[Min(0)]
public int Padding;
[Min(0)]
public int Bleeding;
public bool Translucency;
public BaseImporterAtlasSettings(int padding, int bleeding, bool translucency)
{
Padding = padding;
Bleeding = bleeding;
Translucency = translucency;
}
}
Question:
Why does a plain call to GetField(...)
returns null
in this case while it shouldn't really?
Is this a bug or am I missing something in the docs of GetField
?
Aucun commentaire:
Enregistrer un commentaire