@@ -126,6 +126,34 @@ public bool Equals(EventList? other)
126126 return true ;
127127 }
128128
129+ public bool Equals ( IEventListView ? other )
130+ {
131+ if ( other is null )
132+ {
133+ return false ;
134+ }
135+
136+ if ( Count != other . Count )
137+ {
138+ return false ;
139+ }
140+
141+ if ( ! ReferenceEquals ( DeclaringTypeData . View , other . DeclaringType ) )
142+ {
143+ return false ;
144+ }
145+
146+ for ( int index = 0 ; index < Count ; index ++ )
147+ {
148+ if ( ! Events [ index ] . View . Equals ( other . Events [ index ] ) )
149+ {
150+ return false ;
151+ }
152+ }
153+
154+ return true ;
155+ }
156+
129157 public override bool Equals ( object ? obj )
130158 => obj is EventList other && Equals ( other ) ;
131159
@@ -147,8 +175,189 @@ private int ComputeHashCode()
147175 }
148176 }
149177
150- public static bool operator == ( EventList ? left , EventList ? right )
151- => left ? . Equals ( right ) ?? ( right is null ) ;
152- public static bool operator != ( EventList ? left , EventList ? right )
153- => ! ( left == right ) ;
178+ public static bool operator == ( EventList ? left , EventList ? right ) => left ? . Equals ( right ) ?? ( right is null ) ;
179+ public static bool operator != ( EventList ? left , EventList ? right ) => ! ( left == right ) ;
180+
181+ public static bool operator == ( EventList ? left , IEventListView ? right ) => left ? . Equals ( right ) ?? ( right is null ) ;
182+ public static bool operator != ( EventList ? left , IEventListView ? right ) => ! ( left == right ) ;
183+
184+ public static bool operator == ( IEventListView ? left , EventList ? right ) => right == left ;
185+ public static bool operator != ( IEventListView ? left , EventList ? right ) => ! ( left == right ) ;
186+ }
187+
188+ public sealed class EventListView : IReadOnlyList < IEventDataView > , IEquatable < IEventListView > , IEventListView
189+ {
190+ public static EventListView Empty { get ; } = new EventListView ( ) ;
191+ private readonly int _hashCode ; // precomputed
192+ private readonly ITypeDataView _declaringType ;
193+ private readonly Dictionary < string , IEventDataView > _eventNameIndex ;
194+
195+ public EventListView ( IEventDataView [ ] items , ITypeDataView ? declaringType ) : this ( ( IEnumerable < IEventDataView > ) items , declaringType )
196+ {
197+ }
198+
199+ public EventListView ( IEnumerable < IEventDataView > items , ITypeDataView ? declaringType )
200+ {
201+ ArgumentNullException . ThrowIfNull ( declaringType ) ;
202+
203+ _declaringType = declaringType ;
204+ Events = items ? . ToImmutableList ( ) ?? ImmutableList < IEventDataView > . Empty ;
205+ _eventNameIndex = Events . ToDictionary ( eventData => eventData . Name , StringComparer . Ordinal ) ;
206+
207+ if ( HasItems )
208+ {
209+ ArgumentExceptionAdvanced . ThrowIfAny (
210+ Events ,
211+ eventData => ! ReferenceEquals ( eventData . DeclaringType , _declaringType ) ,
212+ nameof ( items ) ,
213+ $ "At least one item in the argument sequence '{ nameof ( items ) } ' has a different value for the '{ nameof ( IEventDataView ) } .{ nameof ( IEventDataView . DeclaringType ) } ' declaring type handle. All events must belong to the same declaring type.") ;
214+
215+ }
216+
217+ _hashCode = ComputeHashCode ( ) ;
218+ }
219+
220+ internal EventListView ( IEnumerable < IEventDataView > items , ITypeDataView ? declaringType , bool isIntegrityValidationEnabled )
221+ {
222+ ArgumentNullException . ThrowIfNull ( declaringType ) ;
223+
224+ _declaringType = declaringType ;
225+
226+ Events = items ? . ToImmutableList ( ) ?? ImmutableList < IEventDataView > . Empty ;
227+ _eventNameIndex = Events . ToDictionary ( eventData => eventData . Name , StringComparer . Ordinal ) ;
228+
229+ if ( isIntegrityValidationEnabled && HasItems )
230+ {
231+ ArgumentExceptionAdvanced . ThrowIfAny (
232+ Events ,
233+ eventData => ! ReferenceEquals ( eventData . DeclaringType , _declaringType ) ,
234+ nameof ( items ) ,
235+ $ "At least one item in the argument sequence '{ nameof ( items ) } ' has a different value for the '{ nameof ( IEventDataView ) } .{ nameof ( IEventDataView . DeclaringType ) } ' declaring type handle. All events must belong to the same declaring type.") ;
236+
237+ }
238+
239+ _hashCode = ComputeHashCode ( ) ;
240+ }
241+
242+ private EventListView ( )
243+ {
244+ _declaringType = default ! ;
245+ Events = ImmutableList < IEventDataView > . Empty ;
246+ _eventNameIndex = new Dictionary < string , IEventDataView > ( 0 , StringComparer . Ordinal ) ;
247+ _hashCode = ComputeHashCode ( ) ;
248+ }
249+
250+ public bool TryGetEventByName ( string eventName , out IEventDataView ? eventData )
251+ {
252+ ArgumentNullException . ThrowIfNullOrWhiteSpace ( eventName ) ;
253+ return _eventNameIndex . TryGetValue ( eventName , out eventData ) ;
254+ }
255+
256+ public int Count => Events . Count ;
257+ public bool IsEmpty => Events . IsEmpty ;
258+ public bool HasItems => ! IsEmpty ;
259+ public ImmutableList < IEventDataView > Events { get ; }
260+ public ITypeDataView DeclaringType => _declaringType ?? throw new InvalidOperationException ( ExceptionMessages . GetInvalidAccessCollectionEmptyExceptionMessage ( nameof ( EventListView ) , nameof ( DeclaringType ) ) ) ;
261+
262+ public IEventDataView this [ int index ]
263+ {
264+ get
265+ {
266+ ArgumentOutOfRangeException . ThrowIfLessThan ( index , 0 , nameof ( index ) ) ;
267+ ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( index , Events . Count , nameof ( index ) ) ;
268+
269+ return HasItems
270+ ? Events [ index ]
271+ : throw new InvalidOperationException ( ExceptionMessages . GetInvalidAccessCollectionEmptyExceptionMessage ( nameof ( EventList ) , ReflectionConstants . IndexerGetMethodName ) ) ;
272+ }
273+ }
274+
275+ public IEnumerator < IEventDataView > GetEnumerator ( )
276+ => ( ( IEnumerable < IEventDataView > ) Events ) . GetEnumerator ( ) ;
277+
278+ System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ( )
279+ => Events . GetEnumerator ( ) ;
280+
281+ public bool Equals ( IEventListView ? other )
282+ {
283+ if ( other is null )
284+ {
285+ return false ;
286+ }
287+
288+ if ( Count != other . Count )
289+ {
290+ return false ;
291+ }
292+
293+ if ( ! ReferenceEquals ( DeclaringType , other . DeclaringType ) )
294+ {
295+ return false ;
296+ }
297+
298+ for ( int index = 0 ; index < Count ; index ++ )
299+ {
300+ if ( ! Events [ index ] . Equals ( other . Events [ index ] ) )
301+ {
302+ return false ;
303+ }
304+ }
305+
306+ return true ;
307+ }
308+
309+ internal bool Equals ( EventList ? other )
310+ {
311+ if ( other is null )
312+ {
313+ return false ;
314+ }
315+
316+ if ( Count != other . Count )
317+ {
318+ return false ;
319+ }
320+
321+ if ( ! ReferenceEquals ( DeclaringType , other . DeclaringTypeData . View ) )
322+ {
323+ return false ;
324+ }
325+
326+ for ( int index = 0 ; index < Count ; index ++ )
327+ {
328+ if ( ! Events [ index ] . Equals ( other . Events [ index ] . View ) )
329+ {
330+ return false ;
331+ }
332+ }
333+
334+ return true ;
335+ }
336+
337+ public override bool Equals ( object ? obj )
338+ => obj is IEventListView other && Equals ( other ) ;
339+
340+ public override int GetHashCode ( ) => _hashCode ;
341+
342+ private int ComputeHashCode ( )
343+ {
344+ unchecked
345+ {
346+ var hashCode = new HashCode ( ) ;
347+ hashCode . Add ( Count ) ;
348+ hashCode . Add ( DeclaringType ) ;
349+ for ( int index = 0 ; index < Events . Count ; index ++ )
350+ {
351+ hashCode . Add ( Events [ index ] ) ;
352+ }
353+
354+ return hashCode . ToHashCode ( ) ;
355+ }
356+ }
357+
358+ public static bool operator == ( EventListView ? left , IEventListView ? right ) => left ? . Equals ( right ) ?? ( right is null ) ;
359+ public static bool operator != ( EventListView ? left , IEventListView ? right ) => ! ( left == right ) ;
360+
361+ public static bool operator == ( IEventListView ? left , EventListView ? right ) => left ? . Equals ( right ) ?? ( right is null ) ;
362+ public static bool operator != ( IEventListView ? left , EventListView ? right ) => ! ( left == right ) ;
154363}
0 commit comments