diff --git a/src/coreclr/System.Private.CoreLib/src/System/__ComObject.cs b/src/coreclr/System.Private.CoreLib/src/System/__ComObject.cs index 464ebfaff83268..d522a93b475765 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/__ComObject.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/__ComObject.cs @@ -217,24 +217,6 @@ RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(RuntimeTy } else if (interfaceType.Equals(typeof(IEnumerator).TypeHandle)) { - object? enumVariantImpl = GetData(typeof(IEnumeratorOverEnumVARIANTImpl)); - if (enumVariantImpl is null) - { - IntPtr enumVariantPtr = IntPtr.Zero; - try - { IEnumVARIANT enumVariant = (IEnumVARIANT)this; - enumVariantPtr = Marshal.GetIUnknownForObject(enumVariant); - enumVariantImpl = (IEnumerator)EnumeratorToEnumVariantMarshaler.GetInstance(null).MarshalNativeToManaged(enumVariantPtr); - } - finally - { - if (enumVariantPtr != IntPtr.Zero) - { - Marshal.Release(enumVariantPtr); - } - } - SetData(typeof(IEnumeratorOverEnumVARIANTImpl), enumVariantImpl); - } return typeof(IEnumeratorOverEnumVARIANTImpl).TypeHandle; } @@ -313,24 +295,25 @@ private interface ICustomAdapterOverDispatchImpl : ICustomAdapter [DynamicInterfaceCastableImplementation] private interface IEnumeratorOverEnumVARIANTImpl : IEnumerator { + private static IEnumerator GetEnumerator(__ComObject obj) => + ComDataHelpers.GetOrCreateManagedViewFromComData( + obj, static enumVariant => new EnumeratorViewOfEnumVariant(enumVariant)); + bool IEnumerator.MoveNext() { - __ComObject co = (__ComObject)this; - return ((IEnumerator)co.GetData(typeof(IEnumeratorOverEnumVARIANTImpl))!).MoveNext(); + return GetEnumerator((__ComObject)this).MoveNext(); } void IEnumerator.Reset() { - __ComObject co = (__ComObject)this; - ((IEnumerator)co.GetData(typeof(IEnumeratorOverEnumVARIANTImpl))!).Reset(); + GetEnumerator((__ComObject)this).Reset(); } object IEnumerator.Current { get { - __ComObject co = (__ComObject)this; - return ((IEnumerator)co.GetData(typeof(IEnumeratorOverEnumVARIANTImpl))!).Current; + return GetEnumerator((__ComObject)this).Current; } } } diff --git a/src/tests/Interop/COM/Dynamic/CollectionTest.cs b/src/tests/Interop/COM/Dynamic/CollectionTest.cs index b917bae455b6a0..2e5ad9680ead28 100644 --- a/src/tests/Interop/COM/Dynamic/CollectionTest.cs +++ b/src/tests/Interop/COM/Dynamic/CollectionTest.cs @@ -4,7 +4,9 @@ namespace Dynamic { using System; + using System.Collections; using System.Collections.Generic; + using System.Runtime.InteropServices; using Xunit; internal class CollectionTest @@ -81,6 +83,8 @@ private void CustomCollection() Assert.Equal(array[2], obj.Item(2)); Assert.Equal(array.Length, obj.Count); + CustomEnumerator(array); + Console.WriteLine(" + Enumerate collection"); List list = new List(); @@ -135,6 +139,58 @@ private void CustomCollection() Console.WriteLine(" + Clear collection"); obj.Clear(); Assert.Equal(0, obj.Count); + CustomEnumerator(System.Array.Empty()); + } + + private void CustomEnumerator(string[] expected) + { + Console.WriteLine(" + Cast fresh COM enumerators to IEnumerator"); + foreach (string firstMember in new[] { nameof(IEnumerator.MoveNext), nameof(IEnumerator.Reset), nameof(IEnumerator.Current) }) + { + Console.WriteLine($" First member: {firstMember}, items: {expected.Length}"); + object previous = null; + for (int pass = 0; pass < 3; pass++) + { + object enumVariant = obj._NewEnum; + Assert.True(Marshal.IsComObject(enumVariant)); + Assert.NotSame(previous, enumVariant); + previous = enumVariant; + IEnumerator enumerator = (IEnumerator)enumVariant; + List actual = new List(); + + switch (firstMember) + { + case nameof(IEnumerator.MoveNext): + Assert.Equal(expected.Length != 0, enumerator.MoveNext()); + if (expected.Length != 0) + { + actual.Add((string)enumerator.Current); + } + break; + case nameof(IEnumerator.Reset): + enumerator.Reset(); + break; + case nameof(IEnumerator.Current): + Assert.Null(enumerator.Current); + break; + } + + while (enumerator.MoveNext()) + { + actual.Add((string)enumerator.Current); + } + AssertExtensions.CollectionEqual(expected, actual); + Assert.False(enumerator.MoveNext()); + + actual.Clear(); + enumerator.Reset(); + while (enumerator.MoveNext()) + { + actual.Add((string)enumerator.Current); + } + AssertExtensions.CollectionEqual(expected, actual); + } + } } private void IndexChain()