com.wallstop-studios.unity-helpers 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/AGENTS.md +1 -0
  2. package/Docs/ILIST_SORTING_PERFORMANCE.md +16 -16
  3. package/Docs/INDEX.md +1 -0
  4. package/Docs/RANDOM_PERFORMANCE.md +15 -15
  5. package/Docs/REFLECTION_HELPERS.md +84 -1
  6. package/Docs/REFLECTION_PERFORMANCE.md +169 -0
  7. package/{package-lock.json.meta → Docs/REFLECTION_PERFORMANCE.md.meta} +1 -1
  8. package/Docs/RELATIONAL_COMPONENTS.md +6 -0
  9. package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md +63 -0
  10. package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md.meta +7 -0
  11. package/Docs/SPATIAL_TREE_2D_PERFORMANCE.md +64 -64
  12. package/Docs/SPATIAL_TREE_3D_PERFORMANCE.md +64 -64
  13. package/Editor/Sprites/AnimationCopier.cs +1 -1
  14. package/Editor/Sprites/AnimationViewerWindow.cs +4 -4
  15. package/Editor/Sprites/SpriteSettingsApplierAPI.cs +2 -1
  16. package/Editor/Sprites/TextureResizerWizard.cs +4 -3
  17. package/Editor/Utils/ScriptableObjectSingletonCreator.cs +3 -3
  18. package/README.md +8 -3
  19. package/Runtime/Core/Attributes/BaseRelationalComponentAttribute.cs +147 -20
  20. package/Runtime/Core/Attributes/ChildComponentAttribute.cs +630 -117
  21. package/Runtime/Core/Attributes/NotNullAttribute.cs +5 -2
  22. package/Runtime/Core/Attributes/ParentComponentAttribute.cs +477 -103
  23. package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +26 -3
  24. package/Runtime/Core/Attributes/RelationalComponentExtensions.cs +19 -3
  25. package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +265 -92
  26. package/Runtime/Core/CodeGen.meta +8 -0
  27. package/Runtime/Core/DataStructure/ImmutableBitSet.cs +5 -20
  28. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +11 -7
  29. package/Runtime/Core/Helper/Objects.cs +1 -1
  30. package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs +5142 -0
  31. package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs.meta +11 -0
  32. package/Runtime/Core/Helper/ReflectionHelpers.cs +1812 -1518
  33. package/Runtime/Core/Math/Line2D.cs +2 -4
  34. package/Runtime/Core/Math/Line3D.cs +2 -4
  35. package/Runtime/Core/Random/FlurryBurstRandom.cs +0 -6
  36. package/Runtime/Tags/AttributeMetadataCache.cs +4 -6
  37. package/Runtime/Tags/CosmeticEffectData.cs +1 -1
  38. package/Runtime/Visuals/UIToolkit/MultiFileSelectorElement.cs +3 -3
  39. package/Tests/Editor/Helper/HelpersTests.cs +2 -2
  40. package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs +87 -0
  41. package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs.meta +11 -0
  42. package/Tests/Editor/Helper/SpriteHelpersTests.cs +1 -1
  43. package/Tests/Editor/PrefabCheckerReportTests.cs +3 -3
  44. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +18 -12
  45. package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +8 -7
  46. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -1
  47. package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +6 -5
  48. package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +2 -1
  49. package/Tests/Editor/Sprites/SpriteCropperTests.cs +7 -6
  50. package/Tests/Editor/Sprites/SpritePivotAdjusterAdditionalTests.cs +2 -1
  51. package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +4 -3
  52. package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +10 -9
  53. package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +2 -1
  54. package/Tests/Runtime/Helper/ObjectsTests.cs +1 -1
  55. package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs +2923 -0
  56. package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs.meta +11 -0
  57. package/Tests/Runtime/Helper/ReflectionHelperTests.cs +660 -0
  58. package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs +1238 -0
  59. package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs.meta +11 -0
  60. package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs +832 -0
  61. package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs.meta +11 -0
  62. package/package.json +1 -1
  63. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +0 -60
  64. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs.meta +0 -3
@@ -93,12 +93,24 @@ namespace WallstopStudios.UnityHelpers.Tests.Helper
93
93
  return param * 2;
94
94
  }
95
95
 
96
+ public static int StaticMethodTwoParams(int a, int b)
97
+ {
98
+ StaticMethodCallCount++;
99
+ return a + b;
100
+ }
101
+
96
102
  public int InstanceMethodWithParam(string param)
97
103
  {
98
104
  instanceMethodCallCount++;
99
105
  return param?.Length ?? 0;
100
106
  }
101
107
 
108
+ public int InstanceMethodThreeParams(int a, string b, bool c)
109
+ {
110
+ instanceMethodCallCount++;
111
+ return a + (b?.Length ?? 0) + (c ? 1 : 0);
112
+ }
113
+
102
114
  public static void StaticVoidMethodWithParam(int param)
103
115
  {
104
116
  StaticMethodCallCount = param;
@@ -122,6 +134,16 @@ namespace WallstopStudios.UnityHelpers.Tests.Helper
122
134
  StaticMethodCallCount = a + b + c;
123
135
  }
124
136
 
137
+ public static void StaticActionTwo(int a, int b)
138
+ {
139
+ StaticMethodCallCount = a + b;
140
+ }
141
+
142
+ public static void StaticActionFour(int a, int b, int c, int d)
143
+ {
144
+ StaticMethodCallCount = a + b + c + d;
145
+ }
146
+
125
147
  public int InstanceSum(int a, int b)
126
148
  {
127
149
  instanceMethodCallCount++;
@@ -133,6 +155,21 @@ namespace WallstopStudios.UnityHelpers.Tests.Helper
133
155
  instanceMethodCallCount = a + b + c;
134
156
  }
135
157
 
158
+ public void InstanceSetOne(int value)
159
+ {
160
+ instanceMethodCallCount = value;
161
+ }
162
+
163
+ public void InstanceSetTwo(int a, int b)
164
+ {
165
+ instanceMethodCallCount = a + b;
166
+ }
167
+
168
+ public void InstanceSetFour(int a, int b, int c, int d)
169
+ {
170
+ instanceMethodCallCount = a + b + c + d;
171
+ }
172
+
136
173
  public int InstanceSumFour(int a, int b, int c, int d)
137
174
  {
138
175
  instanceMethodCallCount++;
@@ -144,6 +181,11 @@ namespace WallstopStudios.UnityHelpers.Tests.Helper
144
181
  StaticMethodCallCount = 0;
145
182
  instanceMethodCallCount = 0;
146
183
  }
184
+
185
+ public static void ResetStatic()
186
+ {
187
+ StaticMethodCallCount = 0;
188
+ }
147
189
  }
148
190
 
149
191
  public sealed class TestConstructorClass
@@ -217,6 +259,14 @@ namespace WallstopStudios.UnityHelpers.Tests.Helper
217
259
  public int InstanceReadOnlyProperty => 888;
218
260
  }
219
261
 
262
+ public sealed class VariantPropertyClass
263
+ {
264
+ public object ObjectProperty { get; set; } = "instance";
265
+ public static object StaticObjectProperty { get; set; } = "static";
266
+ public object ObjectField = "instance-field";
267
+ public static object StaticObjectField = "static-field";
268
+ }
269
+
220
270
  public sealed class SelfReferentialType
221
271
  {
222
272
  public static SelfReferentialType InstanceField = new();
@@ -1795,6 +1845,616 @@ namespace WallstopStudios.UnityHelpers.Tests.Helper
1795
1845
  Assert.AreEqual(777, getter(dummy));
1796
1846
  }
1797
1847
 
1848
+ [Test]
1849
+ public void TypedPropertyGetterBoxesValueTypeWhenRequested()
1850
+ {
1851
+ PropertyInfo property = typeof(TestPropertyClass).GetProperty(
1852
+ nameof(TestPropertyClass.InstanceProperty)
1853
+ );
1854
+ Func<TestPropertyClass, object> getter = ReflectionHelpers.GetPropertyGetter<
1855
+ TestPropertyClass,
1856
+ object
1857
+ >(property);
1858
+ TestPropertyClass instance = new() { InstanceProperty = 512 };
1859
+ Assert.AreEqual(512, getter(instance));
1860
+ }
1861
+
1862
+ [Test]
1863
+ public void TypedPropertySetterUnboxesValueTypes()
1864
+ {
1865
+ PropertyInfo property = typeof(TestPropertyClass).GetProperty(
1866
+ nameof(TestPropertyClass.InstanceProperty)
1867
+ );
1868
+ Action<TestPropertyClass, object> setter = ReflectionHelpers.GetPropertySetter<
1869
+ TestPropertyClass,
1870
+ object
1871
+ >(property);
1872
+ TestPropertyClass instance = new();
1873
+ setter(instance, 2048);
1874
+ Assert.AreEqual(2048, instance.InstanceProperty);
1875
+ }
1876
+
1877
+ [Test]
1878
+ public void TypedStaticPropertySetterUnboxesValueTypes()
1879
+ {
1880
+ PropertyInfo property = typeof(TestPropertyClass).GetProperty(
1881
+ nameof(TestPropertyClass.StaticProperty)
1882
+ );
1883
+ object original = TestPropertyClass.StaticProperty;
1884
+ try
1885
+ {
1886
+ Action<object> setter = ReflectionHelpers.GetStaticPropertySetter<object>(property);
1887
+ setter(1024);
1888
+ Assert.AreEqual(1024, TestPropertyClass.StaticProperty);
1889
+ }
1890
+ finally
1891
+ {
1892
+ TestPropertyClass.StaticProperty = (int)original;
1893
+ }
1894
+ }
1895
+
1896
+ [Test]
1897
+ public void TypedPropertyGetterCastsReferenceTypes()
1898
+ {
1899
+ VariantPropertyClass instance = new() { ObjectProperty = "hello" };
1900
+ PropertyInfo property = typeof(VariantPropertyClass).GetProperty(
1901
+ nameof(VariantPropertyClass.ObjectProperty)
1902
+ );
1903
+ Func<VariantPropertyClass, string> getter = ReflectionHelpers.GetPropertyGetter<
1904
+ VariantPropertyClass,
1905
+ string
1906
+ >(property);
1907
+ Assert.AreEqual("hello", getter(instance));
1908
+ }
1909
+
1910
+ [Test]
1911
+ public void DynamicIlBoxedFieldGetterReturnsValue()
1912
+ {
1913
+ RunWithDynamicIlOnly(() =>
1914
+ {
1915
+ TestClass instance = new() { intValue = 321 };
1916
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
1917
+ Func<object, object> getter = ReflectionHelpers.GetFieldGetter(field);
1918
+ Assert.AreEqual(321, getter(instance));
1919
+ });
1920
+ }
1921
+
1922
+ [Test]
1923
+ public void DynamicIlBoxedFieldSetterMutatesInstance()
1924
+ {
1925
+ RunWithDynamicIlOnly(() =>
1926
+ {
1927
+ TestClass instance = new();
1928
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
1929
+ Action<object, object> setter = ReflectionHelpers.GetFieldSetter(field);
1930
+ setter(instance, 654);
1931
+ Assert.AreEqual(654, instance.intValue);
1932
+ });
1933
+ }
1934
+
1935
+ [Test]
1936
+ public void DynamicIlTypedFieldSetterMutatesInstance()
1937
+ {
1938
+ RunWithDynamicIlOnly(() =>
1939
+ {
1940
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
1941
+ FieldSetter<TestClass, int> setter = ReflectionHelpers.GetFieldSetter<
1942
+ TestClass,
1943
+ int
1944
+ >(field);
1945
+ TestClass instance = new();
1946
+ setter(ref instance, 987);
1947
+ Assert.AreEqual(987, instance.intValue);
1948
+ });
1949
+ }
1950
+
1951
+ [Test]
1952
+ public void DynamicIlTypedFieldGetterReturnsValue()
1953
+ {
1954
+ RunWithDynamicIlOnly(() =>
1955
+ {
1956
+ TestClass instance = new() { intValue = 741 };
1957
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
1958
+ Func<TestClass, int> getter = ReflectionHelpers.GetFieldGetter<TestClass, int>(
1959
+ field
1960
+ );
1961
+ Assert.AreEqual(741, getter(instance));
1962
+ });
1963
+ }
1964
+
1965
+ [Test]
1966
+ public void DynamicIlTypedStaticFieldSetterMutatesValue()
1967
+ {
1968
+ RunWithDynamicIlOnly(() =>
1969
+ {
1970
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.StaticIntValue));
1971
+ int original = TestClass.StaticIntValue;
1972
+ try
1973
+ {
1974
+ Action<int> setter = ReflectionHelpers.GetStaticFieldSetter<int>(field);
1975
+ setter(512);
1976
+ Assert.AreEqual(512, TestClass.StaticIntValue);
1977
+ }
1978
+ finally
1979
+ {
1980
+ TestClass.StaticIntValue = original;
1981
+ }
1982
+ });
1983
+ }
1984
+
1985
+ [Test]
1986
+ public void DynamicIlTypedPropertySetterMutatesInstance()
1987
+ {
1988
+ RunWithDynamicIlOnly(() =>
1989
+ {
1990
+ PropertyInfo property = typeof(TestPropertyClass).GetProperty(
1991
+ nameof(TestPropertyClass.InstanceProperty)
1992
+ );
1993
+ Action<TestPropertyClass, int> setter = ReflectionHelpers.GetPropertySetter<
1994
+ TestPropertyClass,
1995
+ int
1996
+ >(property);
1997
+ TestPropertyClass instance = new();
1998
+ setter(instance, 222);
1999
+ Assert.AreEqual(222, instance.InstanceProperty);
2000
+ });
2001
+ }
2002
+
2003
+ [Test]
2004
+ public void DynamicIlTypedPropertyGetterReturnsValue()
2005
+ {
2006
+ RunWithDynamicIlOnly(() =>
2007
+ {
2008
+ PropertyInfo property = typeof(TestPropertyClass).GetProperty(
2009
+ nameof(TestPropertyClass.InstanceProperty)
2010
+ );
2011
+ TestPropertyClass instance = new();
2012
+ Func<TestPropertyClass, int> getter = ReflectionHelpers.GetPropertyGetter<
2013
+ TestPropertyClass,
2014
+ int
2015
+ >(property);
2016
+ Assert.AreEqual(instance.InstanceProperty, getter(instance));
2017
+ });
2018
+ }
2019
+
2020
+ [Test]
2021
+ public void DynamicIlTypedStaticPropertySetterMutatesValue()
2022
+ {
2023
+ RunWithDynamicIlOnly(() =>
2024
+ {
2025
+ PropertyInfo property = typeof(TestPropertyClass).GetProperty(
2026
+ nameof(TestPropertyClass.StaticProperty)
2027
+ );
2028
+ int original = TestPropertyClass.StaticProperty;
2029
+ try
2030
+ {
2031
+ Action<int> setter = ReflectionHelpers.GetStaticPropertySetter<int>(property);
2032
+ setter(314);
2033
+ Assert.AreEqual(314, TestPropertyClass.StaticProperty);
2034
+ }
2035
+ finally
2036
+ {
2037
+ TestPropertyClass.StaticProperty = original;
2038
+ }
2039
+ });
2040
+ }
2041
+
2042
+ [Test]
2043
+ public void DynamicIlInstanceMethodInvokerReturnsValue()
2044
+ {
2045
+ RunWithDynamicIlOnly(() =>
2046
+ {
2047
+ MethodInfo method = typeof(TestMethodClass).GetMethod(
2048
+ nameof(TestMethodClass.InstanceMethodWithParam)
2049
+ );
2050
+ Func<object, object[], object> invoker = ReflectionHelpers.GetMethodInvoker(method);
2051
+ TestMethodClass instance = new();
2052
+ object result = invoker(instance, new object[] { "abcd" });
2053
+ Assert.AreEqual(4, result);
2054
+ });
2055
+ }
2056
+
2057
+ [Test]
2058
+ public void DynamicIlTypedInstanceMethodInvokerReturnsValue()
2059
+ {
2060
+ RunWithDynamicIlOnly(() =>
2061
+ {
2062
+ MethodInfo method = typeof(TestMethodClass).GetMethod(
2063
+ nameof(TestMethodClass.InstanceIntMethod)
2064
+ );
2065
+ Func<TestMethodClass, int> invoker = ReflectionHelpers.GetInstanceMethodInvoker<
2066
+ TestMethodClass,
2067
+ int
2068
+ >(method);
2069
+ TestMethodClass instance = new();
2070
+ Assert.AreEqual(100, invoker(instance));
2071
+ });
2072
+ }
2073
+
2074
+ [Test]
2075
+ public void DynamicIlTypedStaticMethodInvokerReturnsValue()
2076
+ {
2077
+ RunWithDynamicIlOnly(() =>
2078
+ {
2079
+ MethodInfo method = typeof(TestMethodClass).GetMethod(
2080
+ nameof(TestMethodClass.StaticIntMethod)
2081
+ );
2082
+ Func<int> invoker = ReflectionHelpers.GetStaticMethodInvoker<int>(method);
2083
+ Assert.AreEqual(42, invoker());
2084
+ });
2085
+ }
2086
+
2087
+ [Test]
2088
+ public void DynamicIlConstructorInvokerCreatesInstance()
2089
+ {
2090
+ RunWithDynamicIlOnly(() =>
2091
+ {
2092
+ ConstructorInfo ctor = typeof(TestConstructorClass).GetConstructor(
2093
+ new[] { typeof(int), typeof(string) }
2094
+ );
2095
+ Func<object[], object> invoker = ReflectionHelpers.GetConstructor(ctor);
2096
+ object created = invoker(new object[] { 5, "five" });
2097
+ Assert.IsInstanceOf<TestConstructorClass>(created);
2098
+ TestConstructorClass instance = (TestConstructorClass)created;
2099
+ Assert.AreEqual(5, instance.Value1);
2100
+ Assert.AreEqual("five", instance.Value2);
2101
+ });
2102
+ }
2103
+
2104
+ [Test]
2105
+ public void DynamicIlParameterlessConstructorCreatesInstance()
2106
+ {
2107
+ RunWithDynamicIlOnly(() =>
2108
+ {
2109
+ Func<TestConstructorClass> ctor =
2110
+ ReflectionHelpers.GetParameterlessConstructor<TestConstructorClass>();
2111
+ TestConstructorClass instance = ctor();
2112
+ Assert.IsNotNull(instance);
2113
+ });
2114
+ }
2115
+
2116
+ [Test]
2117
+ public void DynamicIlIndexerSetterAndGetterRoundTrip()
2118
+ {
2119
+ RunWithDynamicIlOnly(() =>
2120
+ {
2121
+ PropertyInfo indexer = typeof(IndexerClass).GetProperty("Item");
2122
+ Func<object, object[], object> getter = ReflectionHelpers.GetIndexerGetter(indexer);
2123
+ Action<object, object, object[]> setter = ReflectionHelpers.GetIndexerSetter(
2124
+ indexer
2125
+ );
2126
+ IndexerClass instance = new();
2127
+ setter(instance, 13, new object[] { 2 });
2128
+ Assert.AreEqual(13, getter(instance, new object[] { 2 }));
2129
+ });
2130
+ }
2131
+
2132
+ private static void RunWithDynamicIlOnly(Action assertion)
2133
+ {
2134
+ if (!ReflectionHelpers.DynamicIlEnabled)
2135
+ {
2136
+ Assert.Ignore("Dynamic IL is not available on this platform.");
2137
+ }
2138
+
2139
+ using (
2140
+ ReflectionHelpers.OverrideReflectionCapabilities(
2141
+ expressions: false,
2142
+ dynamicIl: true
2143
+ )
2144
+ )
2145
+ {
2146
+ assertion();
2147
+ }
2148
+ }
2149
+
2150
+ [Test]
2151
+ public void TypedPropertySetterCastsReferenceTypes()
2152
+ {
2153
+ VariantPropertyClass instance = new();
2154
+ PropertyInfo property = typeof(VariantPropertyClass).GetProperty(
2155
+ nameof(VariantPropertyClass.ObjectProperty)
2156
+ );
2157
+ Action<VariantPropertyClass, string> setter = ReflectionHelpers.GetPropertySetter<
2158
+ VariantPropertyClass,
2159
+ string
2160
+ >(property);
2161
+ setter(instance, "updated");
2162
+ Assert.AreEqual("updated", instance.ObjectProperty);
2163
+ }
2164
+
2165
+ [Test]
2166
+ public void TypedStaticPropertySetterCastsReferenceTypes()
2167
+ {
2168
+ PropertyInfo property = typeof(VariantPropertyClass).GetProperty(
2169
+ nameof(VariantPropertyClass.StaticObjectProperty)
2170
+ );
2171
+ object original = VariantPropertyClass.StaticObjectProperty;
2172
+ try
2173
+ {
2174
+ Action<string> setter = ReflectionHelpers.GetStaticPropertySetter<string>(property);
2175
+ setter("world");
2176
+ Func<string> getter = ReflectionHelpers.GetStaticPropertyGetter<string>(property);
2177
+ Assert.AreEqual("world", getter());
2178
+ }
2179
+ finally
2180
+ {
2181
+ VariantPropertyClass.StaticObjectProperty = original;
2182
+ }
2183
+ }
2184
+
2185
+ [Test]
2186
+ public void ParameterlessConstructorDelegateCreatesInstances()
2187
+ {
2188
+ Func<object> creator = ReflectionHelpers.GetParameterlessConstructor(
2189
+ typeof(TestConstructorClass)
2190
+ );
2191
+ object first = creator();
2192
+ object second = creator();
2193
+ Assert.IsInstanceOf<TestConstructorClass>(first);
2194
+ Assert.IsInstanceOf<TestConstructorClass>(second);
2195
+ Assert.AreNotSame(first, second);
2196
+ }
2197
+
2198
+ [Test]
2199
+ public void ParameterlessConstructorFallbackUsesReflectionWhenExpressionsDisabled()
2200
+ {
2201
+ using (
2202
+ ReflectionHelpers.OverrideReflectionCapabilities(
2203
+ expressions: false,
2204
+ dynamicIl: false
2205
+ )
2206
+ )
2207
+ {
2208
+ Func<TestConstructorClass> creator =
2209
+ ReflectionHelpers.GetParameterlessConstructor<TestConstructorClass>();
2210
+ TestConstructorClass instance = creator();
2211
+ Assert.IsNotNull(instance);
2212
+ Assert.AreEqual(0, instance.Value1);
2213
+ }
2214
+ }
2215
+
2216
+ [Test]
2217
+ public void ConstructorInvokerCreatesTypedInstance()
2218
+ {
2219
+ ConstructorInfo ctor = typeof(GenericTestClass<int>).GetConstructor(
2220
+ new[] { typeof(int) }
2221
+ );
2222
+ Func<object[], object> invoker = ReflectionHelpers.GetConstructor(ctor);
2223
+ object result = invoker(new object[] { 256 });
2224
+ Assert.IsInstanceOf<GenericTestClass<int>>(result);
2225
+ Assert.AreEqual(256, ((GenericTestClass<int>)result).Value);
2226
+ }
2227
+
2228
+ [Test]
2229
+ public void ConstructorInvokerFallsBackWhenExpressionsDisabled()
2230
+ {
2231
+ ConstructorInfo ctor = typeof(GenericTestClass<int>).GetConstructor(
2232
+ new[] { typeof(int) }
2233
+ );
2234
+ using (
2235
+ ReflectionHelpers.OverrideReflectionCapabilities(
2236
+ expressions: false,
2237
+ dynamicIl: false
2238
+ )
2239
+ )
2240
+ {
2241
+ Func<object[], object> invoker = ReflectionHelpers.GetConstructor(ctor);
2242
+ object result = invoker(new object[] { 64 });
2243
+ Assert.IsInstanceOf<GenericTestClass<int>>(result);
2244
+ Assert.AreEqual(64, ((GenericTestClass<int>)result).Value);
2245
+ }
2246
+ }
2247
+
2248
+ [Test]
2249
+ public void IndexerGetterThrowsOnInvalidIndexCount()
2250
+ {
2251
+ PropertyInfo idxProp = typeof(IndexerClass).GetProperty("Item");
2252
+ Func<object, object[], object> getter = ReflectionHelpers.GetIndexerGetter(idxProp);
2253
+ IndexerClass obj = new();
2254
+ Assert.Throws<IndexOutOfRangeException>(() => getter(obj, Array.Empty<object>()));
2255
+ }
2256
+
2257
+ [Test]
2258
+ public void IndexerHelpersFallbackWhenExpressionsDisabled()
2259
+ {
2260
+ PropertyInfo idxProp = typeof(IndexerClass).GetProperty("Item");
2261
+ using (
2262
+ ReflectionHelpers.OverrideReflectionCapabilities(
2263
+ expressions: false,
2264
+ dynamicIl: false
2265
+ )
2266
+ )
2267
+ {
2268
+ Func<object, object[], object> getter = ReflectionHelpers.GetIndexerGetter(idxProp);
2269
+ Action<object, object, object[]> setter = ReflectionHelpers.GetIndexerSetter(
2270
+ idxProp
2271
+ );
2272
+ IndexerClass obj = new();
2273
+ setter(obj, 99, new object[] { 3 });
2274
+ Assert.AreEqual(99, getter(obj, new object[] { 3 }));
2275
+ }
2276
+ }
2277
+
2278
+ [Test]
2279
+ public void TypedFieldGetterBoxesValueTypeWhenRequested()
2280
+ {
2281
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
2282
+ Func<TestClass, object> getter = ReflectionHelpers.GetFieldGetter<TestClass, object>(
2283
+ field
2284
+ );
2285
+ TestClass instance = new() { intValue = 512 };
2286
+ Assert.AreEqual(512, getter(instance));
2287
+ }
2288
+
2289
+ [Test]
2290
+ public void TypedFieldSetterUnboxesValueTypes()
2291
+ {
2292
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
2293
+ FieldSetter<TestClass, object> setter = ReflectionHelpers.GetFieldSetter<
2294
+ TestClass,
2295
+ object
2296
+ >(field);
2297
+ TestClass instance = new();
2298
+ setter(ref instance, 2048);
2299
+ Assert.AreEqual(2048, instance.intValue);
2300
+ }
2301
+
2302
+ [Test]
2303
+ public void TypedStaticFieldSetterUnboxesValueTypes()
2304
+ {
2305
+ FieldInfo field = typeof(TestClass).GetField(
2306
+ nameof(TestClass.StaticIntValue),
2307
+ BindingFlags.Static | BindingFlags.Public
2308
+ );
2309
+ int original = TestClass.StaticIntValue;
2310
+ try
2311
+ {
2312
+ Action<object> setter = ReflectionHelpers.GetStaticFieldSetter<object>(field);
2313
+ setter(1024);
2314
+ Assert.AreEqual(1024, TestClass.StaticIntValue);
2315
+ }
2316
+ finally
2317
+ {
2318
+ TestClass.StaticIntValue = original;
2319
+ }
2320
+ }
2321
+
2322
+ [Test]
2323
+ public void TypedFieldGetterCastsReferenceTypes()
2324
+ {
2325
+ VariantPropertyClass instance = new() { ObjectField = "hello" };
2326
+ FieldInfo field = typeof(VariantPropertyClass).GetField(
2327
+ nameof(VariantPropertyClass.ObjectField)
2328
+ );
2329
+ Func<VariantPropertyClass, string> getter = ReflectionHelpers.GetFieldGetter<
2330
+ VariantPropertyClass,
2331
+ string
2332
+ >(field);
2333
+ Assert.AreEqual("hello", getter(instance));
2334
+ }
2335
+
2336
+ [Test]
2337
+ public void TypedFieldSetterFallbacksWhenCapabilitiesDisabled()
2338
+ {
2339
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
2340
+ using (
2341
+ ReflectionHelpers.OverrideReflectionCapabilities(
2342
+ expressions: false,
2343
+ dynamicIl: false
2344
+ )
2345
+ )
2346
+ {
2347
+ FieldSetter<TestClass, int> setter = ReflectionHelpers.GetFieldSetter<
2348
+ TestClass,
2349
+ int
2350
+ >(field);
2351
+ TestClass instance = new();
2352
+ setter(ref instance, 321);
2353
+ Assert.AreEqual(321, instance.intValue);
2354
+ }
2355
+ }
2356
+
2357
+ [Test]
2358
+ public void TypedPropertySetterFallbacksWhenCapabilitiesDisabled()
2359
+ {
2360
+ PropertyInfo property = typeof(GenericTestClass<int>).GetProperty(
2361
+ nameof(GenericTestClass<int>.Value)
2362
+ );
2363
+ using (
2364
+ ReflectionHelpers.OverrideReflectionCapabilities(
2365
+ expressions: false,
2366
+ dynamicIl: false
2367
+ )
2368
+ )
2369
+ {
2370
+ Action<GenericTestClass<int>, int> setter = ReflectionHelpers.GetPropertySetter<
2371
+ GenericTestClass<int>,
2372
+ int
2373
+ >(property);
2374
+ GenericTestClass<int> instance = new();
2375
+ setter(instance, 87);
2376
+ Assert.AreEqual(87, instance.Value);
2377
+ }
2378
+ }
2379
+
2380
+ [Test]
2381
+ public void TypedPropertyGetterFallbacksWhenCapabilitiesDisabled()
2382
+ {
2383
+ PropertyInfo property = typeof(GenericTestClass<int>).GetProperty(
2384
+ nameof(GenericTestClass<int>.Value)
2385
+ );
2386
+ GenericTestClass<int> instance = new(45);
2387
+ using (
2388
+ ReflectionHelpers.OverrideReflectionCapabilities(
2389
+ expressions: false,
2390
+ dynamicIl: false
2391
+ )
2392
+ )
2393
+ {
2394
+ Func<GenericTestClass<int>, int> getter = ReflectionHelpers.GetPropertyGetter<
2395
+ GenericTestClass<int>,
2396
+ int
2397
+ >(property);
2398
+ Assert.AreEqual(45, getter(instance));
2399
+ }
2400
+ }
2401
+
2402
+ [Test]
2403
+ public void TypedFieldSetterCastsReferenceTypes()
2404
+ {
2405
+ VariantPropertyClass instance = new();
2406
+ FieldInfo field = typeof(VariantPropertyClass).GetField(
2407
+ nameof(VariantPropertyClass.ObjectField)
2408
+ );
2409
+ FieldSetter<VariantPropertyClass, string> setter = ReflectionHelpers.GetFieldSetter<
2410
+ VariantPropertyClass,
2411
+ string
2412
+ >(field);
2413
+ setter(ref instance, "updated");
2414
+ Assert.AreEqual("updated", instance.ObjectField);
2415
+ }
2416
+
2417
+ [Test]
2418
+ public void TypedStaticFieldSetterCastsReferenceTypes()
2419
+ {
2420
+ FieldInfo field = typeof(VariantPropertyClass).GetField(
2421
+ nameof(VariantPropertyClass.StaticObjectField),
2422
+ BindingFlags.Static | BindingFlags.Public
2423
+ );
2424
+ object original = VariantPropertyClass.StaticObjectField;
2425
+ try
2426
+ {
2427
+ Action<string> setter = ReflectionHelpers.GetStaticFieldSetter<string>(field);
2428
+ setter("world");
2429
+ Func<string> getter = ReflectionHelpers.GetStaticFieldGetter<string>(field);
2430
+ Assert.AreEqual("world", getter());
2431
+ }
2432
+ finally
2433
+ {
2434
+ VariantPropertyClass.StaticObjectField = original;
2435
+ }
2436
+ }
2437
+
2438
+ [Test]
2439
+ public void TypedFieldGetterSupportsFallbackWhenInstanceTypeDiffers()
2440
+ {
2441
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
2442
+ Func<object, int> getter = ReflectionHelpers.GetFieldGetter<object, int>(field);
2443
+ TestClass instance = new() { intValue = 77 };
2444
+ object boxed = instance;
2445
+ Assert.AreEqual(77, getter(boxed));
2446
+ }
2447
+
2448
+ [Test]
2449
+ public void TypedFieldSetterSupportsFallbackWhenInstanceTypeDiffers()
2450
+ {
2451
+ FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.intValue));
2452
+ FieldSetter<object, int> setter = ReflectionHelpers.GetFieldSetter<object, int>(field);
2453
+ object boxed = new TestClass();
2454
+ setter(ref boxed, 88);
2455
+ Assert.AreEqual(88, ((TestClass)boxed).intValue);
2456
+ }
2457
+
1798
2458
  [Test]
1799
2459
  public void TypedStaticInvokerWrongReturnTypeThrows()
1800
2460
  {