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