You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-22 15:06:45 +00:00
C#: Revert marshalling of IDictionary/IEnumerable implementing types
Added marshalling for `System.Collections.Generic.List<T>` and `System.Collections.Generic.Dictionary<TKey, TValue>`.
This commit is contained in:
@@ -15,10 +15,7 @@ namespace Godot.Collections
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return handle == IntPtr.Zero;
|
||||
}
|
||||
get { return handle == IntPtr.Zero; }
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
@@ -43,7 +40,8 @@ namespace Godot.Collections
|
||||
if (collection == null)
|
||||
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
|
||||
|
||||
MarshalUtils.EnumerableToArray(collection, GetPtr());
|
||||
foreach (object element in collection)
|
||||
Add(element);
|
||||
}
|
||||
|
||||
internal Array(ArraySafeHandle handle)
|
||||
@@ -272,14 +270,8 @@ namespace Godot.Collections
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass);
|
||||
}
|
||||
set
|
||||
{
|
||||
objectArray[index] = value;
|
||||
}
|
||||
get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); }
|
||||
set { objectArray[index] = value; }
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
@@ -301,18 +293,12 @@ namespace Godot.Collections
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return objectArray.Count;
|
||||
}
|
||||
get { return objectArray.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return objectArray.IsReadOnly;
|
||||
}
|
||||
get { return objectArray.IsReadOnly; }
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
|
||||
@@ -15,10 +15,7 @@ namespace Godot.Collections
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return handle == IntPtr.Zero;
|
||||
}
|
||||
get { return handle == IntPtr.Zero; }
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
@@ -45,7 +42,8 @@ namespace Godot.Collections
|
||||
if (dictionary == null)
|
||||
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
|
||||
|
||||
MarshalUtils.IDictionaryToDictionary(dictionary, GetPtr());
|
||||
foreach (DictionaryEntry entry in dictionary)
|
||||
Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
internal Dictionary(DictionarySafeHandle handle)
|
||||
@@ -330,14 +328,8 @@ namespace Godot.Collections
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass);
|
||||
}
|
||||
set
|
||||
{
|
||||
objectDict[key] = value;
|
||||
}
|
||||
get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); }
|
||||
set { objectDict[key] = value; }
|
||||
}
|
||||
|
||||
public ICollection<TKey> Keys
|
||||
@@ -385,18 +377,12 @@ namespace Godot.Collections
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return objectDict.Count;
|
||||
}
|
||||
get { return objectDict.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return objectDict.IsReadOnly;
|
||||
}
|
||||
get { return objectDict.IsReadOnly; }
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
@@ -440,7 +426,8 @@ namespace Godot.Collections
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ;
|
||||
return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
|
||||
;
|
||||
}
|
||||
|
||||
// IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
|
||||
@@ -16,10 +16,8 @@ namespace Godot
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
||||
/// </exception>
|
||||
static bool TypeIsGenericArray(Type type)
|
||||
{
|
||||
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
|
||||
}
|
||||
static bool TypeIsGenericArray(Type type) =>
|
||||
type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
|
||||
@@ -28,10 +26,20 @@ namespace Godot
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
||||
/// </exception>
|
||||
static bool TypeIsGenericDictionary(Type type)
|
||||
{
|
||||
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
|
||||
}
|
||||
static bool TypeIsGenericDictionary(Type type) =>
|
||||
type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
|
||||
|
||||
static bool TypeIsSystemGenericList(Type type) =>
|
||||
type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>);
|
||||
|
||||
static bool TypeIsSystemGenericDictionary(Type type) =>
|
||||
type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.Dictionary<,>);
|
||||
|
||||
static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
|
||||
|
||||
static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>);
|
||||
|
||||
static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
|
||||
|
||||
static void ArrayGetElementType(Type arrayType, out Type elementType)
|
||||
{
|
||||
@@ -45,105 +53,6 @@ namespace Godot
|
||||
valueType = genericArgs[1];
|
||||
}
|
||||
|
||||
static bool GenericIEnumerableIsAssignableFromType(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
return true;
|
||||
|
||||
foreach (var interfaceType in type.GetInterfaces())
|
||||
{
|
||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
return true;
|
||||
}
|
||||
|
||||
Type baseType = type.BaseType;
|
||||
|
||||
if (baseType == null)
|
||||
return false;
|
||||
|
||||
return GenericIEnumerableIsAssignableFromType(baseType);
|
||||
}
|
||||
|
||||
static bool GenericIDictionaryIsAssignableFromType(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||||
return true;
|
||||
|
||||
foreach (var interfaceType in type.GetInterfaces())
|
||||
{
|
||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||||
return true;
|
||||
}
|
||||
|
||||
Type baseType = type.BaseType;
|
||||
|
||||
if (baseType == null)
|
||||
return false;
|
||||
|
||||
return GenericIDictionaryIsAssignableFromType(baseType);
|
||||
}
|
||||
|
||||
static bool GenericIEnumerableIsAssignableFromType(Type type, out Type elementType)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
{
|
||||
elementType = type.GetGenericArguments()[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var interfaceType in type.GetInterfaces())
|
||||
{
|
||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
{
|
||||
elementType = interfaceType.GetGenericArguments()[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Type baseType = type.BaseType;
|
||||
|
||||
if (baseType == null)
|
||||
{
|
||||
elementType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return GenericIEnumerableIsAssignableFromType(baseType, out elementType);
|
||||
}
|
||||
|
||||
static bool GenericIDictionaryIsAssignableFromType(Type type, out Type keyType, out Type valueType)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||||
{
|
||||
var genericArgs = type.GetGenericArguments();
|
||||
keyType = genericArgs[0];
|
||||
valueType = genericArgs[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var interfaceType in type.GetInterfaces())
|
||||
{
|
||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||||
{
|
||||
var genericArgs = interfaceType.GetGenericArguments();
|
||||
keyType = genericArgs[0];
|
||||
valueType = genericArgs[1];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Type baseType = type.BaseType;
|
||||
|
||||
if (baseType == null)
|
||||
{
|
||||
keyType = null;
|
||||
valueType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return GenericIDictionaryIsAssignableFromType(baseType, out keyType, out valueType);
|
||||
}
|
||||
|
||||
static Type MakeGenericArrayType(Type elemType)
|
||||
{
|
||||
return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
|
||||
@@ -153,60 +62,5 @@ namespace Godot
|
||||
{
|
||||
return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
|
||||
}
|
||||
|
||||
// TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
|
||||
// TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
|
||||
|
||||
internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
|
||||
{
|
||||
if (enumerable is ICollection collection)
|
||||
{
|
||||
int count = collection.Count;
|
||||
|
||||
object[] tempArray = new object[count];
|
||||
collection.CopyTo(tempArray, 0);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.godot_icall_Array_Add(godotArrayPtr, tempArray[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (object element in enumerable)
|
||||
{
|
||||
Array.godot_icall_Array_Add(godotArrayPtr, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
|
||||
{
|
||||
foreach (DictionaryEntry entry in dictionary)
|
||||
{
|
||||
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void GenericIDictionaryToDictionary(object dictionary, IntPtr godotDictionaryPtr)
|
||||
{
|
||||
#if DEBUG
|
||||
if (!GenericIDictionaryIsAssignableFromType(dictionary.GetType()))
|
||||
throw new InvalidOperationException("The type does not implement IDictionary<,>");
|
||||
#endif
|
||||
|
||||
// TODO: Can we optimize this?
|
||||
|
||||
var keys = ((IEnumerable)dictionary.GetType().GetProperty("Keys").GetValue(dictionary)).GetEnumerator();
|
||||
var values = ((IEnumerable)dictionary.GetType().GetProperty("Values").GetValue(dictionary)).GetEnumerator();
|
||||
|
||||
while (keys.MoveNext() && values.MoveNext())
|
||||
{
|
||||
object key = keys.Current;
|
||||
object value = values.Current;
|
||||
|
||||
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user