Skip to content

Commit 4856c09

Browse files
committed
Add public reflection data view interfaces and refactor API
Introduce IFieldDataView, IParameterDataView, IPropertyDataView, and ITypeDataView for a public, strongly-typed reflection API. Refactor internal data classes to align with these interfaces, using explicit backing fields and direct property accessors. Update related interfaces for type safety and consistency, and rewrite WellKnownFieldDescriptor and WellKnownPropertyDescriptor for clarity and correctness. Remove IDisposable from SymbolInfoData. Apply these changes throughout the codebase, improving robustness, extensibility, and public usability of the reflection API.
1 parent 9b87a26 commit 4856c09

29 files changed

Lines changed: 667 additions & 707 deletions

‎src/BionicCode.Utilities.Net.Profiling/AttributeProfiler.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ private void GetTargetProperties(TypeData typeDataToProfile, bool isFindInstance
747747
foreach (PropertyData propertyData in typeDataToProfile.Properties)
748748
{
749749
cancellationToken.ThrowIfCancellationRequested();
750-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
750+
PropertyInfo propertyInfo = propertyData.GetPropertyInfo;
751751
bool isPropertyStatic = propertyData.IsStatic;
752752
bool isPropertyIndexer = propertyData.IsIndexer;
753753
if (isFindInstanceProviderEnabled
@@ -820,7 +820,7 @@ private void GetInstanceProviderField(TypeData typeDataToProfile, CancellationTo
820820
{
821821
cancellationToken.ThrowIfCancellationRequested();
822822

823-
FieldInfo fieldInfo = fieldData.GetFieldInfo();
823+
FieldInfo fieldInfo = fieldData.GetFieldInfo;
824824
if (fieldData.IsStatic
825825
&& !hasHighPriorityInstanceProvider
826826
&& typeDataToProfile.Type.IsAssignableFrom(fieldData.FieldTypeData.Type))
Lines changed: 55 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,59 @@
1-
namespace BionicCode.Utilities.Net.Reflection
1+
namespace BionicCode.Utilities.Net.Reflection;
2+
3+
using System;
4+
using System.Diagnostics.CodeAnalysis;
5+
6+
/// <summary>
7+
/// Provides a basic fingerprint for a method based on its name, declaring type, return type, parameters and generic method parameters.
8+
/// </summary>
9+
/// <remarks>The <see cref="BasicMethodFingerprint"/> allows to identify methods based on the least required attributes.
10+
/// This allows to identify methods that belong to the same generic family (based on the open generic method signature).<br/>
11+
/// For example, the open generic method would share the same basic fingerprint like all it's closed generic variants.<br/>
12+
/// In other words, the <see cref="BasicMethodFingerprint"/> enables the identification of generic methods that share the same generic structure since it is based on the raw unconstructed generic method signature.</remarks>
13+
internal readonly struct BasicMethodFingerprint : IEquatable<BasicMethodFingerprint>
214
{
3-
using System;
4-
using System.Diagnostics.CodeAnalysis;
5-
6-
/// <summary>
7-
/// Provides a basic fingerprint for a method based on its name, declaring type, return type, parameters and generic method parameters.
8-
/// </summary>
9-
/// <remarks>The <see cref="BasicMethodFingerprint"/> allows to identify methods based on the least required attributes.
10-
/// This allows to identify methods that belong to the same generic family (based on the open generic method signature).<br/>
11-
/// For example, the open generic method would share the same basic fingerprint like all it's closed generic variants.<br/>
12-
/// In other words, the <see cref="BasicMethodFingerprint"/> enables the identification of generic methods that share the same generic structure since it is based on the raw unconstructed generic method signature.</remarks>
13-
internal readonly struct BasicMethodFingerprint : IEquatable<BasicMethodFingerprint>
15+
public BasicMethodFingerprint(string methodName, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle returnTypeHandle, ParameterList parameters, TypeList genericMethodParameters)
1416
{
15-
public BasicMethodFingerprint(string methodName, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle returnTypeHandle, ParameterList parameters, TypeList genericMethodParameters)
16-
{
17-
ArgumentNullException.ThrowIfNullOrWhiteSpace(methodName, nameof(methodName));
18-
ArgumentNullExceptionAdvanced.ThrowIfDefault(declaringTypeHandle, nameof(declaringTypeHandle));
19-
ArgumentNullExceptionAdvanced.ThrowIfDefault(returnTypeHandle, nameof(returnTypeHandle));
20-
ArgumentNullException.ThrowIfNull(parameters, nameof(parameters));
21-
ArgumentNullException.ThrowIfNull(genericMethodParameters, nameof(genericMethodParameters));
22-
23-
MethodName = methodName;
24-
DeclaringTypeData = declaringTypeHandle;
25-
ReturnTypeData = returnTypeHandle;
26-
Parameters = parameters;
27-
GenericMethodParameters = genericMethodParameters;
28-
29-
_hashCode = ComputeHashCode();
30-
}
31-
32-
public string MethodName { get; }
33-
public RuntimeTypeHandle DeclaringTypeData { get; }
34-
public RuntimeTypeHandle ReturnTypeData { get; }
35-
public ParameterList Parameters { get; }
36-
public TypeList GenericMethodParameters { get; }
37-
private readonly int _hashCode;
38-
39-
public bool Equals(BasicMethodFingerprint other) => MethodName.Equals(other.MethodName, StringComparison.Ordinal)
40-
&& DeclaringTypeData.Equals(other.DeclaringTypeData)
41-
&& ReturnTypeData.Equals(other.ReturnTypeData)
42-
&& Parameters == other.Parameters
43-
&& GenericMethodParameters == other.GenericMethodParameters;
44-
45-
public override bool Equals([NotNullWhen(true)] object? obj)
46-
=> obj is BasicMethodFingerprint basicMethodFingerprint && Equals(basicMethodFingerprint);
47-
public override int GetHashCode()
48-
=> _hashCode;
49-
50-
private int ComputeHashCode()
51-
{
52-
return HashCode.Combine(
53-
MethodName,
54-
DeclaringTypeData,
55-
ReturnTypeData,
56-
Parameters,
57-
GenericMethodParameters);
58-
}
59-
60-
public static bool operator ==(BasicMethodFingerprint left, BasicMethodFingerprint right) => left.Equals(right);
61-
public static bool operator !=(BasicMethodFingerprint left, BasicMethodFingerprint right) => !(left == right);
17+
ArgumentNullException.ThrowIfNullOrWhiteSpace(methodName, nameof(methodName));
18+
ArgumentNullExceptionAdvanced.ThrowIfDefault(declaringTypeHandle, nameof(declaringTypeHandle));
19+
ArgumentNullExceptionAdvanced.ThrowIfDefault(returnTypeHandle, nameof(returnTypeHandle));
20+
ArgumentNullException.ThrowIfNull(parameters, nameof(parameters));
21+
ArgumentNullException.ThrowIfNull(genericMethodParameters, nameof(genericMethodParameters));
22+
23+
MethodName = methodName;
24+
DeclaringTypeData = declaringTypeHandle;
25+
ReturnTypeData = returnTypeHandle;
26+
Parameters = parameters;
27+
GenericMethodParameters = genericMethodParameters;
28+
29+
_hashCode = ComputeHashCode();
6230
}
31+
32+
public string MethodName { get; }
33+
public RuntimeTypeHandle DeclaringTypeData { get; }
34+
public RuntimeTypeHandle ReturnTypeData { get; }
35+
public ParameterList Parameters { get; }
36+
public TypeList GenericMethodParameters { get; }
37+
private readonly int _hashCode;
38+
39+
public bool Equals(BasicMethodFingerprint other) => MethodName.Equals(other.MethodName, StringComparison.Ordinal)
40+
&& DeclaringTypeData.Equals(other.DeclaringTypeData)
41+
&& ReturnTypeData.Equals(other.ReturnTypeData)
42+
&& Parameters == other.Parameters
43+
&& GenericMethodParameters == other.GenericMethodParameters;
44+
45+
public override bool Equals([NotNullWhen(true)] object? obj)
46+
=> obj is BasicMethodFingerprint basicMethodFingerprint && Equals(basicMethodFingerprint);
47+
public override int GetHashCode()
48+
=> _hashCode;
49+
50+
private int ComputeHashCode() => HashCode.Combine(
51+
MethodName,
52+
DeclaringTypeData,
53+
ReturnTypeData,
54+
Parameters,
55+
GenericMethodParameters);
56+
57+
public static bool operator ==(BasicMethodFingerprint left, BasicMethodFingerprint right) => left.Equals(right);
58+
public static bool operator !=(BasicMethodFingerprint left, BasicMethodFingerprint right) => !(left == right);
6359
}

‎src/BionicCode.Utilities.Reflection/ConstructorData.cs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ internal ConstructorData(SymbolReflectionInfoCacheKey symbolInfoDataCacheKey)
3838

3939
Handle = symbolInfoDataCacheKey.ConstructorDescriptor.ConstructorInfo.MethodHandle;
4040
ConstructorInfo = symbolInfoDataCacheKey.ConstructorDescriptor.ConstructorInfo;
41+
DeclaringTypeHandle = ConstructorInfo.DeclaringType?.TypeHandle ?? throw new InvalidOperationException("Declaring type handle is not available.");
42+
ImplementingTypeHandle = DeclaringTypeHandle;
43+
IsExplicitInterfaceImplementation = false;
4144
}
4245

43-
public ConstructorInfo ConstructorInfo { get; }
46+
internal ConstructorInfo ConstructorInfo { get; }
4447

45-
public override MethodBase GetMethodBase() => ConstructorInfo;
48+
internal override MethodBase GetMethodBase() => ConstructorInfo;
4649

4750
protected override MemberInfo GetMemberInfo() => ConstructorInfo;
4851

‎src/BionicCode.Utilities.Reflection/DelegateProvider.cs‎

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ public static MethodData GetOrCreateFastEventInvoker(EventData eventData)
558558
ArgumentNullException.ThrowIfNull(fieldData, nameof(fieldData));
559559
ArgumentNullException.ThrowIfNull(fieldData.DeclaringTypeData, nameof(fieldData));
560560

561-
FieldInfo field = fieldData.GetFieldInfo();
561+
FieldInfo field = fieldData.FieldInfo;
562562

563563
// (object? propertyType) => (object?)((TDeclaring)propertyType).Field
564564
ParameterExpression targetParam = Expression.Parameter(typeof(object), "propertyType");
@@ -619,7 +619,7 @@ public static MethodData GetOrCreateFastEventInvoker(EventData eventData)
619619
ParameterExpression targetParam = Expression.Parameter(typeof(object), "propertyType");
620620
ParameterExpression valueParam = Expression.Parameter(typeof(object), "returnType");
621621

622-
FieldInfo field = fieldData.GetFieldInfo();
622+
FieldInfo field = fieldData.FieldInfo;
623623
Expression fieldAccess =
624624
fieldData.IsStatic
625625
? Expression.Field(expression: null, field)
@@ -693,7 +693,7 @@ public static ValueTypeMemberSetter<TTarget, TValue> CreateStructSetter<TTarget,
693693
ParameterExpression targetByRef = Expression.Parameter(targetType.MakeByRefType(), "propertyType");
694694
ParameterExpression valueParam = Expression.Parameter(valueType, "returnType");
695695

696-
FieldInfo field = fieldData.GetFieldInfo();
696+
FieldInfo field = fieldData.FieldInfo;
697697
MemberExpression fieldAccess = Expression.Field(targetByRef, field);
698698
BinaryExpression assign = Expression.Assign(fieldAccess, Expression.Convert(valueParam, fieldType));
699699
BlockExpression body = Expression.Block(assign, Expression.Empty());
@@ -735,7 +735,7 @@ public static ValueTypeMemberSetter<TTarget, TValue> CreateStructSetter<TTarget,
735735
// (object? target) => (object?)((TDeclaring)target).Property
736736
ParameterExpression targetParam = Expression.Parameter(typeof(object), "target");
737737

738-
PropertyInfo property = propertyData.GetPropertyInfo();
738+
PropertyInfo property = propertyData.PropertyInfo;
739739
Type declaringType = propertyData.DeclaringTypeData.Type;
740740
Expression propertyAccess =
741741
propertyData.IsStatic
@@ -808,7 +808,7 @@ public static PropertyGetter<TTarget, TValue> CreateGetter<TTarget, TValue>(Prop
808808
? Expression.Convert(targetParam, declaringType)
809809
: targetParam;
810810

811-
PropertyInfo property = propertyData.GetPropertyInfo();
811+
PropertyInfo property = propertyData.PropertyInfo;
812812
Expression propertyAccess = Expression.Property(instanceExpression, property);
813813

814814
Expression body;
@@ -932,7 +932,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex> CreateIndexerGetter
932932
: targetParam;
933933

934934
// Access the indexer: propertyType[index]
935-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
935+
PropertyInfo propertyInfo = propertyData.PropertyInfo;
936936
IndexExpression propertyAccess = Expression.MakeIndex(instanceExpression, propertyInfo, indexExpressions);
937937

938938
Expression body;
@@ -1048,7 +1048,7 @@ public static IndexerPropertyGetter<TTarget, TValue> CreateIndexerGetter<TTarget
10481048
: targetParam;
10491049

10501050
// Access the indexer: propertyType[index]
1051-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
1051+
PropertyInfo propertyInfo = propertyData.PropertyInfo;
10521052
IndexExpression propertyAccess = Expression.MakeIndex(instanceExpression, propertyInfo, indexExpressions);
10531053

10541054
Expression body;
@@ -1179,7 +1179,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex1, TIndex2> CreateInd
11791179
: targetParam;
11801180

11811181
// Access the indexer: propertyType[index1, index2]
1182-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
1182+
PropertyInfo propertyInfo = propertyData.PropertyInfo;
11831183
IndexExpression propertyAccess = Expression.MakeIndex(instanceExpression, propertyInfo, [castedIndex1Param, castedIndex2Param]);
11841184

11851185
Expression body;
@@ -1333,7 +1333,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex1, TIndex2, TIndex3>
13331333
: targetParam;
13341334

13351335
// Access the indexer: propertyType[index1, index2, index3]
1336-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
1336+
PropertyInfo propertyInfo = propertyData.PropertyInfo;
13371337
IndexExpression propertyAccess = Expression.MakeIndex(instanceExpression, propertyInfo, [castedIndex1Param, castedIndex2Param, castedIndex3Param]);
13381338

13391339
Expression body;
@@ -1433,7 +1433,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex1, TIndex2, TIndex3>
14331433
: Expression.Convert(targetParam, declaringType);
14341434

14351435
// Access the indexer: propertyType[index0, index1, ...]
1436-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
1436+
PropertyInfo propertyInfo = propertyData.PropertyInfo;
14371437
IndexExpression propertyAccess = Expression.MakeIndex(instanceExpression, propertyInfo, indexExpressions);
14381438

14391439
// Box the result
@@ -1487,7 +1487,7 @@ public static IndexerPropertyGetter<TTarget, TValue, TIndex1, TIndex2, TIndex3>
14871487
ParameterExpression targetParam = Expression.Parameter(typeof(object), "target");
14881488
ParameterExpression valueParam = Expression.Parameter(typeof(object), "value");
14891489

1490-
PropertyInfo property = propertyData.GetPropertyInfo();
1490+
PropertyInfo property = propertyData.PropertyInfo;
14911491
Expression propertyAccess =
14921492
propertyData.IsStatic
14931493
? Expression.Property(expression: null, property)
@@ -1570,7 +1570,7 @@ public static PropertySetter<TTarget, TValue> CreateSetter<TTarget, TValue>(Prop
15701570
ParameterExpression targetParam = Expression.Parameter(targetType, "target");
15711571
ParameterExpression valueParam = Expression.Parameter(valueType, "value");
15721572

1573-
PropertyInfo property = propertyData.GetPropertyInfo();
1573+
PropertyInfo property = propertyData.PropertyInfo;
15741574
Expression propertyAccess =
15751575
propertyData.IsStatic
15761576
? Expression.Property(expression: null, property)
@@ -1687,7 +1687,7 @@ public static PropertySetter<TTarget, TValue> CreateSetter<TTarget, TValue>(Prop
16871687
}
16881688

16891689
// Access the indexer: propertyType[index0, index1, ...]
1690-
PropertyInfo propertyInfo = propertyData.GetPropertyInfo();
1690+
PropertyInfo propertyInfo = propertyData.PropertyInfo;
16911691

16921692
Type declaringType = propertyData.DeclaringTypeData.Type;
16931693
Expression? instanceExpression = propertyData.IsStatic
@@ -1759,7 +1759,7 @@ public static ValueTypePropertySetter<TTarget, TValue> CreateStructSetter<TTarge
17591759
ParameterExpression targetByRef = Expression.Parameter(refTargetType, "target");
17601760
ParameterExpression valueParam = Expression.Parameter(typeof(TValue), "value");
17611761

1762-
PropertyInfo property = propertyData.GetPropertyInfo();
1762+
PropertyInfo property = propertyData.PropertyInfo;
17631763
MemberExpression propertyAccess = Expression.Property(targetByRef, property);
17641764

17651765
UnaryExpression castedValue;
@@ -1823,7 +1823,7 @@ public static ValueTypePropertySetter CreateStructSetter(PropertyData propertyDa
18231823
ParameterExpression targetParam = Expression.Parameter(targetType, "target");
18241824
ParameterExpression valueParam = Expression.Parameter(valueType, "value");
18251825

1826-
PropertyInfo property = propertyData.GetPropertyInfo();
1826+
PropertyInfo property = propertyData.PropertyInfo;
18271827
MemberExpression propertyAccess = Expression.Property(targetParam, property);
18281828

18291829
UnaryExpression castedValue = null;
@@ -1930,7 +1930,7 @@ public static ValueTypeIndexerPropertySetter<TTarget, TValue> CreateStructIndexe
19301930
indexExpressions[i] = convertedIndex;
19311931
}
19321932

1933-
PropertyInfo property = propertyData.GetPropertyInfo();
1933+
PropertyInfo property = propertyData.PropertyInfo;
19341934

19351935
Expression? instanceExpression = Expression.Convert(targetByRef, declaringType);
19361936
IndexExpression propertyAccess = Expression.MakeIndex(instanceExpression, property, indexExpressions);

‎src/BionicCode.Utilities.Reflection/EventData.cs‎

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ internal sealed class EventData : MemberData
3434
private TypeData? _eventHandlerTypeData;
3535
private string? _assemblyName;
3636
private SymbolComponentInfo? _symbolComponentInfo;
37-
private EventInfo _eventInfo;
3837
private readonly WellKnownEventDescriptor _descriptor;
3938
private RuntimeTypeHandle? _declaringTypeHandle;
4039
private RuntimeTypeHandle? _implementingTypeHandle;
@@ -147,17 +146,7 @@ private void ThrowIfInvalidMethodArguments(object?[]? args)
147146
? SymbolReflectionInfoCache.GetOrCreateSymbolInfoDataCacheEntry(eventHandlerType)
148147
: throw new NotSupportedException($"The underlying '{typeof(EventInfo).FullName}' for event '{EventInfo.Name}' does not have an event handler type.");
149148

150-
public EventInfo EventInfo
151-
{
152-
get
153-
{
154-
ExceptionThrower.ThrowIfDisposed(this);
155-
156-
return base.IsDisposed ? throw new ObjectDisposedException(nameof(EventData)) : _eventInfo;
157-
}
158-
159-
private set => _eventInfo = value;
160-
}
149+
public EventInfo EventInfo { get; }
161150

162151
/// <inheritdoc/>
163152
public override bool IsExplicitInterfaceImplementation => _isExplicitInterfaceImplementation ??= IsExplicitImplementation(this);
@@ -291,10 +280,4 @@ private static SymbolAttributes GetAttributesInternal(EventData eventData)
291280
private static AccessModifier GetAccessModifierInternal(EventData eventData) => eventData is EventData checkedEventData
292281
? checkedEventData.AddMethodData?.AccessModifier ?? AccessModifier.Undefined
293282
: throw new ArgumentNullException(nameof(eventData));
294-
295-
protected override void Dispose(bool disposing)
296-
{
297-
base.Dispose(disposing);
298-
EventInfo = null!;
299-
}
300283
}

0 commit comments

Comments
 (0)