mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-17 14:37:49 +08:00
Add support for writing to IList<T>'s which don't implement IList
This commit is contained in:
parent
5aef8ddc99
commit
b062924af7
@ -14,8 +14,40 @@ using UnhollowerBaseLib;
|
|||||||
|
|
||||||
namespace UnityExplorer.Tests
|
namespace UnityExplorer.Tests
|
||||||
{
|
{
|
||||||
|
public class TestIndexer : IList<int>
|
||||||
|
{
|
||||||
|
private readonly List<int> list = new List<int>() { 1,2,3,4,5 };
|
||||||
|
|
||||||
|
public int Count => list.Count;
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
int IList<int>.this[int index]
|
||||||
|
{
|
||||||
|
get => list[index];
|
||||||
|
set => list[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(int item) => list.IndexOf(item);
|
||||||
|
public bool Contains(int item) => list.Contains(item);
|
||||||
|
|
||||||
|
public void Add(int item) => list.Add(item);
|
||||||
|
public void Insert(int index, int item) => list.Insert(index, item);
|
||||||
|
|
||||||
|
public bool Remove(int item) => list.Remove(item);
|
||||||
|
public void RemoveAt(int index) => list.RemoveAt(index);
|
||||||
|
|
||||||
|
public void Clear() => list.Clear();
|
||||||
|
|
||||||
|
public void CopyTo(int[] array, int arrayIndex) => list.CopyTo(array, arrayIndex);
|
||||||
|
|
||||||
|
public IEnumerator<int> GetEnumerator() => list.GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => list.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
public static class TestClass
|
public static class TestClass
|
||||||
{
|
{
|
||||||
|
public static readonly TestIndexer AAAAATest = new TestIndexer();
|
||||||
|
|
||||||
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
|
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
|
||||||
{
|
{
|
||||||
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");
|
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");
|
||||||
|
@ -19,7 +19,7 @@ namespace UnityExplorer
|
|||||||
public static class ExplorerCore
|
public static class ExplorerCore
|
||||||
{
|
{
|
||||||
public const string NAME = "UnityExplorer";
|
public const string NAME = "UnityExplorer";
|
||||||
public const string VERSION = "4.0.0";
|
public const string VERSION = "4.0.1";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.unityexplorer";
|
public const string GUID = "com.sinai.unityexplorer";
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.UI.CacheObject;
|
||||||
@ -19,11 +20,14 @@ namespace UnityExplorer.UI.IValues
|
|||||||
object ICacheObjectController.Target => this.CurrentOwner.Value;
|
object ICacheObjectController.Target => this.CurrentOwner.Value;
|
||||||
public Type TargetType { get; private set; }
|
public Type TargetType { get; private set; }
|
||||||
|
|
||||||
public override bool CanWrite => base.CanWrite && RefIList != null && !RefIList.IsReadOnly;
|
public override bool CanWrite => base.CanWrite && ((RefIList != null && !RefIList.IsReadOnly) || IsWritableGenericIList);
|
||||||
|
|
||||||
public Type EntryType;
|
public Type EntryType;
|
||||||
public IList RefIList;
|
public IList RefIList;
|
||||||
|
|
||||||
|
private bool IsWritableGenericIList;
|
||||||
|
private PropertyInfo genericIndexer;
|
||||||
|
|
||||||
public int ItemCount => values.Count;
|
public int ItemCount => values.Count;
|
||||||
private readonly List<object> values = new List<object>();
|
private readonly List<object> values = new List<object>();
|
||||||
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
|
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
|
||||||
@ -92,6 +96,12 @@ namespace UnityExplorer.UI.IValues
|
|||||||
{
|
{
|
||||||
RefIList = value as IList;
|
RefIList = value as IList;
|
||||||
|
|
||||||
|
// Check if the type implements IList<T> but not IList (ie. Il2CppArrayBase)
|
||||||
|
if (RefIList == null)
|
||||||
|
CheckGenericIList(value);
|
||||||
|
else
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
|
||||||
values.Clear();
|
values.Clear();
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
@ -141,14 +151,61 @@ namespace UnityExplorer.UI.IValues
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckGenericIList(object value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var type = value.GetType();
|
||||||
|
if (type.GetInterfaces().Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||||
|
IsWritableGenericIList = !(bool)type.GetProperty("IsReadOnly").GetValue(value, null);
|
||||||
|
else
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
|
||||||
|
if (IsWritableGenericIList)
|
||||||
|
{
|
||||||
|
// Find the "this[int index]" property.
|
||||||
|
// It might be a private implementation.
|
||||||
|
foreach (var prop in type.GetProperties(ReflectionUtility.FLAGS))
|
||||||
|
{
|
||||||
|
if ((prop.Name == "Item"
|
||||||
|
|| (prop.Name.StartsWith("System.Collections.Generic.IList<") && prop.Name.EndsWith(">.Item")))
|
||||||
|
&& prop.GetIndexParameters() is ParameterInfo[] parameters
|
||||||
|
&& parameters.Length == 1
|
||||||
|
&& parameters[0].ParameterType == typeof(int))
|
||||||
|
{
|
||||||
|
genericIndexer = prop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (genericIndexer == null)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Failed to find indexer property for IList<T> type '{type.FullName}'!");
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception processing IEnumerable for IList<T> check: {ex.ReflectionExToString()}");
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setting the value of an index to the list
|
// Setting the value of an index to the list
|
||||||
|
|
||||||
public void TrySetValueToIndex(object value, int index)
|
public void TrySetValueToIndex(object value, int index)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//value = value.TryCast(this.EntryType);
|
if (!IsWritableGenericIList)
|
||||||
|
{
|
||||||
RefIList[index] = value;
|
RefIList[index] = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genericIndexer.SetValue(CurrentOwner.Value, value, new object[] { index });
|
||||||
|
}
|
||||||
|
|
||||||
var entry = cachedEntries[index];
|
var entry = cachedEntries[index];
|
||||||
entry.SetValueFromSource(value);
|
entry.SetValueFromSource(value);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user