1
0
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:
Ignacio Etcheverry
2020-04-23 02:19:32 +02:00
parent 28f0b15c9d
commit 20b9dbb1d5
13 changed files with 328 additions and 500 deletions

View File

@@ -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)

View File

@@ -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>>

View File

@@ -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);
}
}
}
}