Skip to content

Commit a39b548

Browse files
committed
Update indexer delegate docs and add index validation
Generalize XML docs to support multi-dimensional indexers. Wrap indexer setter delegates with index length validation. Fix PropertyData invoker generics to use non-nullable TTarget.
1 parent fb541b9 commit a39b548

File tree

2 files changed

+17
-13
lines changed

2 files changed

+17
-13
lines changed

src/BionicCode.Utilities.Reflection/DelegateProvider.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ public static PropertyGetter<TTarget, TValue> CreateGetter<TTarget, TValue>(Prop
837837
/// indexer with at least one index parameter.</param>
838838
/// <returns>A delegate that gets the value of the specified indexer property for a given declaringType object and index.</returns>
839839
/// <exception cref="InvalidOperationException">Thrown if the specified property already has a getter invoker generated.</exception>
840-
/// <exception cref="ArgumentException">Thrown if the specified property is not a 1D indexer, or is static, or if the types specified by <typeparamref name="TTarget"/>, <typeparamref name="TIndex"/>, or <typeparamref name="TValue"/> are not compatible with the declaring type, index parameter type, or property type.</exception>
840+
/// <exception cref="ArgumentException">Thrown if the specified property is not an indexer, or is static, or if the types specified by <typeparamref name="TTarget"/>, <typeparamref name="TIndex"/>, or <typeparamref name="TValue"/> are not compatible with the declaring type, index parameter type, or property type.</exception>
841841
/// <exception cref="ArgumentNullException">Thrown if <paramref name="propertyData"/> or its declaring type data is <see langword="null">.</exception>"
842842
public static IndexerPropertyGetter<TTarget, TValue, TIndex> CreateIndexerGetter<TTarget, TValue, TIndex>(PropertyData propertyData)
843843
{
@@ -874,6 +874,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex> CreateIndexerGetter
874874

875875
// Validate indices length
876876
Expression validationExpression = CreateIndexParameterArrayLengthMismatchExceptionExpression(propertyData, indicesParam, isGetter: true);
877+
877878
Type indexType = typeof(TIndex);
878879
ParameterList propertyGetMethodParameters = propertyData.PropertyGetMethodParameters;
879880

@@ -950,7 +951,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex> CreateIndexerGetter
950951
/// indexer with exactly one index parameter.</param>
951952
/// <returns>A delegate that gets the value of the specified static indexer property for a given declaringType object and index.</returns>
952953
/// <exception cref="InvalidOperationException">Thrown if the specified property already has a getter invoker generated.</exception>
953-
/// <exception cref="ArgumentException">Thrown if the specified property is not a 1D static indexer, or not static, or if the types specified by <typeparamref name="TIndex"/>, or <typeparamref name="TValue"/> are not compatible with the index parameter type, or property type.</exception>
954+
/// <exception cref="ArgumentException">Thrown if the specified property is not an static indexer, or not static, or if the types specified by <typeparamref name="TIndex"/>, or <typeparamref name="TValue"/> are not compatible with the index parameter type, or property type.</exception>
954955
/// <exception cref="ArgumentNullException">Thrown if <paramref name="propertyData"/> or its declaring type data is <see langword="null">.</exception>"
955956
public static IndexerPropertyGetter<object?, TValue, TIndex> CreateStaticIndexerGetter<TValue, TIndex>(PropertyData propertyData)
956957
{
@@ -1803,7 +1804,7 @@ public static ValueTypePropertySetter<TTarget, TValue> CreateStructSetter<TTarge
18031804
/// <summary>
18041805
/// Creates a delegate that sets the value of a non-static indexer property on a reference type instance.
18051806
/// </summary>
1806-
/// <remarks>Use this method to generate a performant setter for non-static 1D indexer properties when
1807+
/// <remarks>Use this method to generate a performant setter for non-static indexer properties when
18071808
/// reflection-based property access is required.</remarks>
18081809
/// <typeparam name="TTarget">The reference type that declares the indexer property. Must be a class.</typeparam>
18091810
/// <typeparam name="TValue">The type of the value to set on the indexer property.</typeparam>
@@ -1812,7 +1813,7 @@ public static ValueTypePropertySetter<TTarget, TValue> CreateStructSetter<TTarge
18121813
/// <returns>A delegate that sets the value of the specified 3D indexer property on a reference type instance using the provided
18131814
/// indices and value type.</returns>
18141815
/// <exception cref="InvalidOperationException">Thrown if the specified property already has a set invoker generated.</exception>
1815-
/// <exception cref="ArgumentException">Thrown if the property is declared on a value type,or is read-only, static, or if the provided generic method arguments are incompatible or if the property is not a 1D indexer.</exception>"
1816+
/// <exception cref="ArgumentException">Thrown if the property is declared on a value type,or is read-only, static, or if the provided generic method arguments are incompatible or if the property is not a indexer.</exception>"
18161817
public static IndexerPropertySetter<TTarget?, TValue, TIndex> CreateIndexerSetter<TTarget, TValue, TIndex>(PropertyData propertyData)
18171818
where TTarget : class?
18181819
{
@@ -1908,16 +1909,17 @@ public static ValueTypePropertySetter<TTarget, TValue> CreateStructSetter<TTarge
19081909

19091910
// Action<...> requires a void body -> wrap assignment in a void block.
19101911
BlockExpression body = Expression.Block(assign, Expression.Empty());
1912+
BlockExpression guardedBody = Expression.Block(validationExpression, body);
19111913

19121914
return Expression
1913-
.Lambda<IndexerPropertySetter<TTarget?, TValue, TIndex>>(body, targetParam, valueParam, indicesParam)
1915+
.Lambda<IndexerPropertySetter<TTarget?, TValue, TIndex>>(guardedBody, targetParam, valueParam, indicesParam)
19141916
.Compile();
19151917
}
19161918

19171919
/// <summary>
19181920
/// Creates a delegate that sets the value of a non-static indexer property on a reference type instance.
19191921
/// </summary>
1920-
/// <remarks>Use this method to generate a performant setter for non-static 1D indexer properties when
1922+
/// <remarks>Use this method to generate a performant setter for non-static indexer properties when
19211923
/// reflection-based property access is required.</remarks>
19221924
/// <typeparam name="TTarget">The reference type that declares the indexer property. Must be a class.</typeparam>
19231925
/// <typeparam name="TValue">The type of the value to set on the indexer property.</typeparam>
@@ -1926,7 +1928,7 @@ public static ValueTypePropertySetter<TTarget, TValue> CreateStructSetter<TTarge
19261928
/// <returns>A delegate that sets the value of the specified 3D indexer property on a reference type instance using the provided
19271929
/// indices and value type.</returns>
19281930
/// <exception cref="InvalidOperationException">Thrown if the specified property already has a set invoker generated.</exception>
1929-
/// <exception cref="ArgumentException">Thrown if the property is read-only, static, or if the provided generic method arguments are incompatible or if the property is not a 1D indexer.</exception>"
1931+
/// <exception cref="ArgumentException">Thrown if the property is read-only, static, or if the provided generic method arguments are incompatible or if the property is not an indexer.</exception>"
19301932
public static IndexerPropertySetter<object?, TValue, TIndex> CreateStaticIndexerSetter<TValue, TIndex>(PropertyData propertyData)
19311933
{
19321934
ArgumentNullException.ThrowIfNull(propertyData);
@@ -2014,9 +2016,10 @@ public static ValueTypePropertySetter<TTarget, TValue> CreateStructSetter<TTarge
20142016

20152017
// Action<...> requires a void body -> wrap assignment in a void block.
20162018
BlockExpression body = Expression.Block(assign, Expression.Empty());
2019+
BlockExpression guardedBody = Expression.Block(validationExpression, body);
20172020

20182021
return Expression
2019-
.Lambda<IndexerPropertySetter<object?, TValue, TIndex>>(body, targetParam, valueParam, indicesParam)
2022+
.Lambda<IndexerPropertySetter<object?, TValue, TIndex>>(guardedBody, targetParam, valueParam, indicesParam)
20202023
.Compile();
20212024
}
20222025

@@ -2131,9 +2134,10 @@ public static ValueTypeIndexerPropertySetter<TTarget, TValue, TIndex> CreateStru
21312134

21322135
// Action<...> requires a void body -> wrap assignment in a void block.
21332136
BlockExpression body = Expression.Block(assign, Expression.Empty());
2137+
BlockExpression guardedBody = Expression.Block(validationExpression, body);
21342138

21352139
return Expression
2136-
.Lambda<ValueTypeIndexerPropertySetter<TTarget, TValue, TIndex>>(body, targetByRef, valueParam, indicesParam)
2140+
.Lambda<ValueTypeIndexerPropertySetter<TTarget, TValue, TIndex>>(guardedBody, targetByRef, valueParam, indicesParam)
21372141
.Compile();
21382142
}
21392143

src/BionicCode.Utilities.Reflection/PropertyData.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ internal void SetValue<TTarget, TValue>(TTarget? target, TValue value) where TTa
364364
nameof(target),
365365
$"Type mismatch. Reason: The instance type {targetType.ToFullyQualifiedSignatureName()} is not assignable to {DeclaringTypeData.FullyQualifiedSignature}");
366366

367-
PropertySetter<TTarget?, TValue> propertySetInvoker = GetSetInvokerInternal<TTarget?, TValue>();
367+
PropertySetter<TTarget?, TValue> propertySetInvoker = GetSetInvokerInternal<TTarget, TValue>();
368368
propertySetInvoker(target, value);
369369
}
370370
}
@@ -576,7 +576,7 @@ internal void SetIndexerValue<TTarget, TValue, TIndex>(TTarget? target, TValue v
576576
nameof(target),
577577
$"Type mismatch. Reason: The instance type {targetType.ToFullyQualifiedSignatureName()} is not assignable to {DeclaringTypeData.FullyQualifiedSignature}");
578578

579-
IndexerPropertySetter<TTarget?, TValue, TIndex> staticPropertySetInvoker = GetIndexerSetInvokerInternal<TTarget?, TValue, TIndex>();
579+
IndexerPropertySetter<TTarget?, TValue, TIndex> staticPropertySetInvoker = GetIndexerSetInvokerInternal<TTarget, TValue, TIndex>();
580580
staticPropertySetInvoker(target, value, indices!);
581581
}
582582
}
@@ -692,7 +692,7 @@ internal void SetIndexerValue<TTarget, TValue, TIndex1, TIndex2>(TTarget? target
692692
nameof(target),
693693
$"Type mismatch. Reason: The instance type {targetType.ToFullyQualifiedSignatureName()} is not assignable to {DeclaringTypeData.FullyQualifiedSignature}");
694694

695-
IndexerPropertySetter<TTarget?, TValue, TIndex1, TIndex2> staticPropertySetInvoker = Get2DIndexerSetInvokerInternal<TTarget?, TValue, TIndex1, TIndex2>();
695+
IndexerPropertySetter<TTarget?, TValue, TIndex1, TIndex2> staticPropertySetInvoker = Get2DIndexerSetInvokerInternal<TTarget, TValue, TIndex1, TIndex2>();
696696
staticPropertySetInvoker(target, value, index1, index2);
697697
}
698698
}
@@ -807,7 +807,7 @@ internal void SetIndexerValue<TTarget, TValue, TIndex1, TIndex2, TIndex3>(TTarge
807807
nameof(target),
808808
$"Type mismatch. Reason: The instance type {targetType.ToFullyQualifiedSignatureName()} is not assignable to {DeclaringTypeData.FullyQualifiedSignature}");
809809

810-
IndexerPropertySetter<TTarget?, TValue, TIndex1, TIndex2, TIndex3> staticPropertySetInvoker = Get3DIndexerSetInvokerInternal<TTarget?, TValue, TIndex1, TIndex2, TIndex3>();
810+
IndexerPropertySetter<TTarget?, TValue, TIndex1, TIndex2, TIndex3> staticPropertySetInvoker = Get3DIndexerSetInvokerInternal<TTarget, TValue, TIndex1, TIndex2, TIndex3>();
811811
staticPropertySetInvoker(target, value, index1, index2, index3);
812812
}
813813
}

0 commit comments

Comments
 (0)