Add attributes support for dotnet interop for methods, fields and properties
This commit is contained in:
@@ -49,6 +49,7 @@ namespace FlaxEngine.Interop
|
||||
internal struct NativePropertyDefinitions
|
||||
{
|
||||
internal IntPtr name;
|
||||
internal ManagedHandle propertyHandle;
|
||||
internal ManagedHandle getterHandle;
|
||||
internal ManagedHandle setterHandle;
|
||||
internal uint getterAttributes;
|
||||
@@ -379,6 +380,17 @@ namespace FlaxEngine.Interop
|
||||
for (int i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var property = properties[i];
|
||||
|
||||
ManagedHandle propertyHandle = ManagedHandle.Alloc(property);
|
||||
#if FLAX_EDITOR
|
||||
if (type.IsCollectible)
|
||||
propertyHandleCacheCollectible.Add(propertyHandle);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
propertyHandleCache.Add(propertyHandle);
|
||||
}
|
||||
|
||||
IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativePropertyDefinitions>() * i);
|
||||
|
||||
var getterMethod = property.GetGetMethod(true);
|
||||
@@ -387,6 +399,7 @@ namespace FlaxEngine.Interop
|
||||
var classProperty = new NativePropertyDefinitions
|
||||
{
|
||||
name = NativeAllocStringAnsi(property.Name),
|
||||
propertyHandle = propertyHandle,
|
||||
};
|
||||
if (getterMethod != null)
|
||||
{
|
||||
@@ -404,12 +417,8 @@ namespace FlaxEngine.Interop
|
||||
*classPropertiesCount = properties.Length;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
internal static void GetAttributes(object[] attributeValues, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
{
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
object[] attributeValues = type.GetCustomAttributes(false);
|
||||
|
||||
ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf<ManagedHandle>());
|
||||
for (int i = 0; i < attributeValues.Length; i++)
|
||||
{
|
||||
@@ -424,6 +433,38 @@ namespace FlaxEngine.Interop
|
||||
*classAttributesCount = attributeValues.Length;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
{
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
object[] attributeValues = type.GetCustomAttributes(false);
|
||||
GetAttributes(attributeValues, classAttributes, classAttributesCount);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetMethodAttributes(ManagedHandle methodHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
{
|
||||
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
|
||||
object[] attributeValues = methodHolder.method.GetCustomAttributes(false);
|
||||
GetAttributes(attributeValues, classAttributes, classAttributesCount);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetFieldAttributes(ManagedHandle fieldHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
{
|
||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||
object[] attributeValues = field.field.GetCustomAttributes(false);
|
||||
GetAttributes(attributeValues, classAttributes, classAttributesCount);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetPropertyAttributes(ManagedHandle propertyHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
{
|
||||
PropertyInfo property = Unsafe.As<PropertyInfo>(propertyHandle.Target);
|
||||
object[] attributeValues = property.GetCustomAttributes(false);
|
||||
GetAttributes(attributeValues, classAttributes, classAttributesCount);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle)
|
||||
{
|
||||
@@ -1027,6 +1068,9 @@ namespace FlaxEngine.Interop
|
||||
foreach (var handle in fieldHandleCacheCollectible)
|
||||
handle.Free();
|
||||
fieldHandleCacheCollectible.Clear();
|
||||
foreach (var handle in propertyHandleCacheCollectible)
|
||||
handle.Free();
|
||||
propertyHandleCacheCollectible.Clear();
|
||||
|
||||
_typeSizeCache.Clear();
|
||||
|
||||
|
||||
@@ -38,11 +38,13 @@ namespace FlaxEngine.Interop
|
||||
private static ConcurrentDictionary<IntPtr, Delegate> cachedDelegates = new();
|
||||
private static Dictionary<Type, (TypeHolder typeHolder, ManagedHandle handle)> managedTypes = new(new TypeComparer());
|
||||
private static List<ManagedHandle> fieldHandleCache = new();
|
||||
private static List<ManagedHandle> propertyHandleCache = new();
|
||||
#if FLAX_EDITOR
|
||||
private static List<ManagedHandle> methodHandlesCollectible = new();
|
||||
private static ConcurrentDictionary<IntPtr, Delegate> cachedDelegatesCollectible = new();
|
||||
private static Dictionary<Type, (TypeHolder typeHolder, ManagedHandle handle)> managedTypesCollectible = new(new TypeComparer());
|
||||
private static List<ManagedHandle> fieldHandleCacheCollectible = new();
|
||||
private static List<ManagedHandle> propertyHandleCacheCollectible = new();
|
||||
#endif
|
||||
private static Dictionary<object, ManagedHandle> classAttributesCacheCollectible = new();
|
||||
private static Dictionary<Assembly, ManagedHandle> assemblyHandles = new();
|
||||
|
||||
@@ -16,6 +16,8 @@ class FLAXENGINE_API MProperty
|
||||
protected:
|
||||
#if USE_MONO
|
||||
MonoProperty* _monoProperty;
|
||||
#elif USE_NETCORE
|
||||
void* _handle;
|
||||
#endif
|
||||
|
||||
mutable MMethod* _getMethod;
|
||||
@@ -34,7 +36,7 @@ public:
|
||||
#if USE_MONO
|
||||
explicit MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass);
|
||||
#elif USE_NETCORE
|
||||
MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes);
|
||||
MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -211,7 +211,25 @@ MClass* GetClass(MType* typeHandle);
|
||||
MClass* GetOrCreateClass(MType* typeHandle);
|
||||
MType* GetObjectType(MObject* obj);
|
||||
|
||||
void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass);
|
||||
void* GetCustomAttribute(const Array<MObject*>& attributes, const MClass* attributeClass)
|
||||
{
|
||||
for (MObject* attr : attributes)
|
||||
{
|
||||
MClass* attrClass = MCore::Object::GetClass(attr);
|
||||
if (attrClass == attributeClass)
|
||||
return attr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GetCustomAttributes(Array<MObject*>& result, void* handle, void* getAttributesFunc)
|
||||
{
|
||||
MObject** attributes;
|
||||
int numAttributes;
|
||||
CallStaticMethod<void, void*, MObject***, int*>(getAttributesFunc, handle, &attributes, &numAttributes);
|
||||
result.Set(attributes, numAttributes);
|
||||
MCore::GC::FreeMemory(attributes);
|
||||
}
|
||||
|
||||
// Structures used to pass information from runtime, must match with the structures in managed side
|
||||
struct NativeClassDefinitions
|
||||
@@ -244,6 +262,7 @@ struct NativeFieldDefinitions
|
||||
struct NativePropertyDefinitions
|
||||
{
|
||||
const char* name;
|
||||
void* propertyHandle;
|
||||
void* getterHandle;
|
||||
void* setterHandle;
|
||||
MMethodAttributes getterAttributes;
|
||||
@@ -1089,7 +1108,7 @@ const Array<MProperty*>& MClass::GetProperties() const
|
||||
for (int i = 0; i < numProperties; i++)
|
||||
{
|
||||
const NativePropertyDefinitions& definition = foundProperties[i];
|
||||
MProperty* property = New<MProperty>(const_cast<MClass*>(this), definition.name, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes);
|
||||
MProperty* property = New<MProperty>(const_cast<MClass*>(this), definition.name, definition.propertyHandle, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes);
|
||||
_properties[i] = property;
|
||||
MCore::GC::FreeMemory((void*)definition.name);
|
||||
}
|
||||
@@ -1125,7 +1144,7 @@ const Array<MClass*>& MClass::GetInterfaces() const
|
||||
|
||||
bool MClass::HasAttribute(const MClass* klass) const
|
||||
{
|
||||
return GetCustomAttribute(this, klass) != nullptr;
|
||||
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
|
||||
}
|
||||
|
||||
bool MClass::HasAttribute() const
|
||||
@@ -1135,7 +1154,7 @@ bool MClass::HasAttribute() const
|
||||
|
||||
MObject* MClass::GetAttribute(const MClass* klass) const
|
||||
{
|
||||
return (MObject*)GetCustomAttribute(this, klass);
|
||||
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
|
||||
}
|
||||
|
||||
const Array<MObject*>& MClass::GetAttributes() const
|
||||
@@ -1145,14 +1164,8 @@ const Array<MObject*>& MClass::GetAttributes() const
|
||||
ScopeLock lock(BinaryModule::Locker);
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
|
||||
MObject** attributes;
|
||||
int numAttributes;
|
||||
static void* GetClassAttributesPtr = GetStaticMethodPointer(TEXT("GetClassAttributes"));
|
||||
CallStaticMethod<void, void*, MObject***, int*>(GetClassAttributesPtr, _handle, &attributes, &numAttributes);
|
||||
_attributes.Set(attributes, numAttributes);
|
||||
MCore::GC::FreeMemory(attributes);
|
||||
|
||||
GetCustomAttributes(_attributes, _handle, GetClassAttributesPtr);
|
||||
_hasCachedAttributes = true;
|
||||
return _attributes;
|
||||
}
|
||||
@@ -1191,17 +1204,17 @@ MMethod* MEvent::GetRemoveMethod() const
|
||||
|
||||
bool MEvent::HasAttribute(const MClass* klass) const
|
||||
{
|
||||
return false; // TODO: implement MEvent in .NET
|
||||
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
|
||||
}
|
||||
|
||||
bool MEvent::HasAttribute() const
|
||||
{
|
||||
return false; // TODO: implement MEvent in .NET
|
||||
return !GetAttributes().IsEmpty();
|
||||
}
|
||||
|
||||
MObject* MEvent::GetAttribute(const MClass* klass) const
|
||||
{
|
||||
return nullptr; // TODO: implement MEvent in .NET
|
||||
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
|
||||
}
|
||||
|
||||
const Array<MObject*>& MEvent::GetAttributes() const
|
||||
@@ -1313,29 +1326,29 @@ void MField::SetValue(MObject* instance, void* value) const
|
||||
|
||||
bool MField::HasAttribute(const MClass* klass) const
|
||||
{
|
||||
// TODO: implement MField attributes in .NET
|
||||
return false;
|
||||
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
|
||||
}
|
||||
|
||||
bool MField::HasAttribute() const
|
||||
{
|
||||
// TODO: implement MField attributes in .NET
|
||||
return false;
|
||||
return !GetAttributes().IsEmpty();
|
||||
}
|
||||
|
||||
MObject* MField::GetAttribute(const MClass* klass) const
|
||||
{
|
||||
// TODO: implement MField attributes in .NET
|
||||
return nullptr;
|
||||
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
|
||||
}
|
||||
|
||||
const Array<MObject*>& MField::GetAttributes() const
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
ScopeLock lock(BinaryModule::Locker);
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
static void* GetFieldAttributesPtr = GetStaticMethodPointer(TEXT("GetFieldAttributes"));
|
||||
GetCustomAttributes(_attributes, _handle, GetFieldAttributesPtr);
|
||||
_hasCachedAttributes = true;
|
||||
|
||||
// TODO: implement MField attributes in .NET
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
@@ -1475,35 +1488,36 @@ bool MMethod::GetParameterIsOut(int32 paramIdx) const
|
||||
|
||||
bool MMethod::HasAttribute(const MClass* klass) const
|
||||
{
|
||||
// TODO: implement MMethod attributes in .NET
|
||||
return false;
|
||||
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
|
||||
}
|
||||
|
||||
bool MMethod::HasAttribute() const
|
||||
{
|
||||
// TODO: implement MMethod attributes in .NET
|
||||
return false;
|
||||
return !GetAttributes().IsEmpty();
|
||||
}
|
||||
|
||||
MObject* MMethod::GetAttribute(const MClass* klass) const
|
||||
{
|
||||
// TODO: implement MMethod attributes in .NET
|
||||
return nullptr;
|
||||
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
|
||||
}
|
||||
|
||||
const Array<MObject*>& MMethod::GetAttributes() const
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
ScopeLock lock(BinaryModule::Locker);
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
static void* GetMethodAttributesPtr = GetStaticMethodPointer(TEXT("GetMethodAttributes"));
|
||||
GetCustomAttributes(_attributes, _handle, GetMethodAttributesPtr);
|
||||
_hasCachedAttributes = true;
|
||||
|
||||
// TODO: implement MMethod attributes in .NET
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
MProperty::MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes)
|
||||
MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes)
|
||||
: _parentClass(parentClass)
|
||||
, _name(name)
|
||||
, _handle(handle)
|
||||
, _hasCachedAttributes(false)
|
||||
{
|
||||
_hasGetMethod = getterHandle != nullptr;
|
||||
@@ -1552,29 +1566,29 @@ void MProperty::SetValue(MObject* instance, void* value, MObject** exception) co
|
||||
|
||||
bool MProperty::HasAttribute(const MClass* klass) const
|
||||
{
|
||||
// TODO: implement MProperty attributes in .NET
|
||||
return false;
|
||||
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
|
||||
}
|
||||
|
||||
bool MProperty::HasAttribute() const
|
||||
{
|
||||
// TODO: implement MProperty attributes in .NET
|
||||
return false;
|
||||
return !GetAttributes().IsEmpty();
|
||||
}
|
||||
|
||||
MObject* MProperty::GetAttribute(const MClass* klass) const
|
||||
{
|
||||
// TODO: implement MProperty attributes in .NET
|
||||
return nullptr;
|
||||
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
|
||||
}
|
||||
|
||||
const Array<MObject*>& MProperty::GetAttributes() const
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
ScopeLock lock(BinaryModule::Locker);
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
static void* GetPropertyAttributesPtr = GetStaticMethodPointer(TEXT("GetPropertyAttributes"));
|
||||
GetCustomAttributes(_attributes, _handle, GetPropertyAttributesPtr);
|
||||
_hasCachedAttributes = true;
|
||||
|
||||
// TODO: implement MProperty attributes in .NET
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
@@ -1637,18 +1651,6 @@ MType* GetObjectType(MObject* obj)
|
||||
return (MType*)typeHandle;
|
||||
}
|
||||
|
||||
void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass)
|
||||
{
|
||||
const Array<MObject*>& attributes = klass->GetAttributes();
|
||||
for (MObject* attr : attributes)
|
||||
{
|
||||
MClass* attrClass = MCore::Object::GetClass(attr);
|
||||
if (attrClass == attributeClass)
|
||||
return attr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if DOTNET_HOST_CORECLR
|
||||
|
||||
const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.Interop.NativeInterop, FlaxEngine.CSharp");
|
||||
|
||||
Reference in New Issue
Block a user