[Foundation] Make the generic collection classes' generic GetEnumerator methods public. (#20808)

When finding an enumerator for the given code:

```cs
var collection = new NSSet<NSNumber> ();
foreach (var item in collection) {
	// ...
}
```

the C# compiler will first look for any `GetEnumerator` methods. The non-generic `NSSet` class defines a `IEnumerator<NSObject> GetEnumerator<NSObject> ()` method, which, since the generic `NSSet<T>` class doesn't define such a method, is selected.

The end result is that the type of the foreach element is `NSObject`
(`GetEnumerator`'s return type') - which is somewhat unexpected:

```cs
var collection = new NSSet<NSNumber> ();
foreach (var item in collection) {
	Console.WriteLine (item.LongValue); // error CS1061: 'NSObject' does not contain a definition for 'LongValue'
}
```

The fix is to define a  `IEnumerator<T> GetEnumerator<T> ()` method in the
generic `NSSet<T>` class, which the C# will find and choose over the base
class' method. Then the type of the foreach element is the correct type, and
the following code works:

```cs
var collection = new NSSet<NSNumber> ();
foreach (var item in collection) {
	Console.WriteLine (item.LongValue); // it works!
}
```

Do this for all our generic collection classes.

Also document these methods + all the other public `GetEnumerator` methods.
This commit is contained in:
Rolf Bjarne Kvinge 2024-07-03 20:16:53 +02:00 коммит произвёл GitHub
Родитель 95df610900
Коммит 323d28c220
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
19 изменённых файлов: 96 добавлений и 12 удалений

Просмотреть файл

@ -476,7 +476,9 @@ namespace Foundation {
return ToArray<NSObject> ();
}
IEnumerator<NSObject> IEnumerable<NSObject>.GetEnumerator ()
/// <summary>Returns an enumerator that iterates through the array.</summary>
/// <returns>An enumerator that can be used to iterate through the array.</returns>
public IEnumerator<NSObject> GetEnumerator ()
{
return new NSFastEnumerator<NSObject> (this);
}

Просмотреть файл

@ -77,7 +77,9 @@ namespace Foundation {
}
#region IEnumerable<TKey>
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
/// <summary>Returns an enumerator that iterates through the array.</summary>
/// <returns>An enumerator that can be used to iterate through the array.</returns>
public new IEnumerator<TKey> GetEnumerator ()
{
return new NSFastEnumerator<TKey> (this);
}

Просмотреть файл

@ -395,6 +395,8 @@ namespace Foundation {
return GetEnumerator ();
}
/// <summary>Returns an enumerator that iterates through the dictionary.</summary>
/// <returns>An enumerator that can be used to iterate through the dictionary.</returns>
public IEnumerator<KeyValuePair<NSObject, NSObject>> GetEnumerator ()
{
foreach (var key in Keys) {

Просмотреть файл

@ -47,6 +47,8 @@ namespace Foundation {
}
}
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public IEnumerator<nuint> GetEnumerator ()
{
if (this.Count == 0)

Просмотреть файл

@ -185,6 +185,8 @@ namespace Foundation {
}
#region IEnumerable<T> implementation
/// <summary>Returns an enumerator that iterates through the array.</summary>
/// <returns>An enumerator that can be used to iterate through the array.</returns>
public IEnumerator<TValue> GetEnumerator ()
{
return new NSFastEnumerator<TValue> (this);

Просмотреть файл

@ -311,6 +311,8 @@ namespace Foundation {
#endregion
#region IEnumerable<K,V>
/// <summary>Returns an enumerator that iterates through the dictionary.</summary>
/// <returns>An enumerator that can be used to iterate through the dictionary.</returns>
public IEnumerator<KeyValuePair<NSObject, NSObject>> GetEnumerator ()
{
foreach (var key in Keys) {

Просмотреть файл

@ -157,7 +157,9 @@ namespace Foundation {
}
#region IEnumerable<TKey>
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public new IEnumerator<TKey> GetEnumerator ()
{
return new NSFastEnumerator<TKey> (this);
}

Просмотреть файл

@ -162,7 +162,9 @@ namespace Foundation {
}
#region IEnumerable<T> implementation
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public new IEnumerator<TKey> GetEnumerator ()
{
return new NSFastEnumerator<TKey> (this);
}

Просмотреть файл

@ -72,6 +72,8 @@ namespace Foundation {
return (NSOrderedSet) Runtime.GetNSObject (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr (class_ptr, Selector.GetHandle (selSetWithArray), a.Handle));
}
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public IEnumerator<NSObject> GetEnumerator ()
{
var enumerator = _GetEnumerator ();

Просмотреть файл

@ -109,7 +109,9 @@ namespace Foundation {
}
#region IEnumerable<TKey>
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public new IEnumerator<TKey> GetEnumerator ()
{
return new NSFastEnumerator<TKey> (this);
}

Просмотреть файл

@ -66,6 +66,8 @@ namespace Foundation {
}
#region IEnumerable<T>
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public IEnumerator<NSObject> GetEnumerator ()
{
var enumerator = _GetEnumerator ();

Просмотреть файл

@ -127,7 +127,9 @@ namespace Foundation {
}
#region IEnumerable<TKey>
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
/// <summary>Returns an enumerator that iterates through the set.</summary>
/// <returns>An enumerator that can be used to iterate through the set.</returns>
public new IEnumerator<TKey> GetEnumerator ()
{
return new NSFastEnumerator<TKey> (this);
}

Просмотреть файл

@ -33206,7 +33206,6 @@ M:Foundation.NSDictionary.FromObjectsAndKeys(Foundation.NSObject[],Foundation.NS
M:Foundation.NSDictionary.FromObjectsAndKeys(Foundation.NSObject[],Foundation.NSObject[])
M:Foundation.NSDictionary.FromObjectsAndKeys(System.Object[],System.Object[],System.IntPtr)
M:Foundation.NSDictionary.FromObjectsAndKeys(System.Object[],System.Object[])
M:Foundation.NSDictionary.GetEnumerator
M:Foundation.NSDictionary.LowlevelObjectForKey(System.IntPtr)
M:Foundation.NSDictionary.ToFileAttributes
M:Foundation.NSDictionary.TryGetValue(Foundation.NSObject,Foundation.NSObject@)
@ -33389,7 +33388,6 @@ M:Foundation.NSIndexSet.EncodeTo(Foundation.NSCoder)
M:Foundation.NSIndexSet.FromArray(System.Int32[])
M:Foundation.NSIndexSet.FromArray(System.UInt32[])
M:Foundation.NSIndexSet.FromArray(System.UIntPtr[])
M:Foundation.NSIndexSet.GetEnumerator
M:Foundation.NSIndexSet.ToArray
M:Foundation.NSInflectionRule.EncodeTo(Foundation.NSCoder)
M:Foundation.NSInputStream.Dispose(System.Boolean)
@ -33506,7 +33504,6 @@ M:Foundation.NSMutableArray`1.#ctor(System.UIntPtr)
M:Foundation.NSMutableArray`1.Add(`0)
M:Foundation.NSMutableArray`1.AddObjects(`0[])
M:Foundation.NSMutableArray`1.Contains(`0)
M:Foundation.NSMutableArray`1.GetEnumerator
M:Foundation.NSMutableArray`1.IndexOf(`0)
M:Foundation.NSMutableArray`1.Insert(`0,System.IntPtr)
M:Foundation.NSMutableArray`1.InsertObjects(`0[],Foundation.NSIndexSet)
@ -33545,7 +33542,6 @@ M:Foundation.NSMutableDictionary.FromObjectsAndKeys(Foundation.NSObject[],Founda
M:Foundation.NSMutableDictionary.FromObjectsAndKeys(Foundation.NSObject[],Foundation.NSObject[])
M:Foundation.NSMutableDictionary.FromObjectsAndKeys(System.Object[],System.Object[],System.IntPtr)
M:Foundation.NSMutableDictionary.FromObjectsAndKeys(System.Object[],System.Object[])
M:Foundation.NSMutableDictionary.GetEnumerator
M:Foundation.NSMutableDictionary.LowlevelFromObjectAndKey(System.IntPtr,System.IntPtr)
M:Foundation.NSMutableDictionary.LowlevelSetObject(Foundation.NSObject,System.IntPtr)
M:Foundation.NSMutableDictionary.LowlevelSetObject(System.IntPtr,System.IntPtr)
@ -33810,7 +33806,6 @@ M:Foundation.NSOrderedSet.#ctor(System.String[])
M:Foundation.NSOrderedSet.Contains(System.Object)
M:Foundation.NSOrderedSet.EncodeTo(Foundation.NSCoder)
M:Foundation.NSOrderedSet.Equals(System.Object)
M:Foundation.NSOrderedSet.GetEnumerator
M:Foundation.NSOrderedSet.GetHashCode
M:Foundation.NSOrderedSet.MakeNSOrderedSet``1(`0[])
M:Foundation.NSOrderedSet.op_Addition(Foundation.NSOrderedSet,Foundation.NSOrderedSet)
@ -33913,7 +33908,6 @@ M:Foundation.NSSet.#ctor(System.Object[])
M:Foundation.NSSet.#ctor(System.String[])
M:Foundation.NSSet.Contains(System.Object)
M:Foundation.NSSet.EncodeTo(Foundation.NSCoder)
M:Foundation.NSSet.GetEnumerator
M:Foundation.NSSet.MakeNSObjectSet``1(`0[])
M:Foundation.NSSet.op_Addition(Foundation.NSSet,Foundation.NSOrderedSet)
M:Foundation.NSSet.op_Addition(Foundation.NSSet,Foundation.NSSet)

Просмотреть файл

@ -81,6 +81,17 @@ namespace MonoTouchFixtures.Foundation {
Assert.AreEqual (C, lst.Count, "iterator count");
}
[Test]
public void IEnumerable1Test_EnumeratorType ()
{
var myEnumerable = new NSArray<NSNumber> ();
foreach (var item in myEnumerable) {
// The point of this test is to verify that the compiler finds the correct enumerator (the one returning NSNumbers, and not the one from the non-generic NSSet class returning NSObjects).
// This means that we don't have to actually execute this code, it's enough to make it compile.
Console.WriteLine (item.LongValue);
}
}
[Test]
public void FromNSObjectsNullTest ()
{

Просмотреть файл

@ -233,5 +233,16 @@ namespace MonoTouchFixtures.Foundation {
Assert.AreEqual (C, lst.Count, "iterator count");
}
}
[Test]
public void IEnumerable1Test_EnumeratorType ()
{
var myEnumerable = new NSMutableArray<NSNumber> ();
foreach (var item in myEnumerable) {
// The point of this test is to verify that the compiler finds the correct enumerator (the one returning NSNumbers, and not the one from the non-generic NSSet class returning NSObjects).
// This means that we don't have to actually execute this code, it's enough to make it compile.
Console.WriteLine (item.LongValue);
}
}
}
}

Просмотреть файл

@ -259,6 +259,17 @@ namespace MonoTouchFixtures.Foundation {
Assert.AreEqual (C, lst.Count, "iterator count");
}
[Test]
public void IEnumerable1Test_EnumeratorType ()
{
var myEnumerable = new NSMutableOrderedSet<NSNumber> ();
foreach (var item in myEnumerable) {
// The point of this test is to verify that the compiler finds the correct enumerator (the one returning NSNumbers, and not the one from the non-generic NSSet class returning NSObjects).
// This means that we don't have to actually execute this code, it's enough to make it compile.
Console.WriteLine (item.LongValue);
}
}
[Test]
public void IEnumerableTest ()
{

Просмотреть файл

@ -225,6 +225,17 @@ namespace MonoTouchFixtures.Foundation {
}
}
[Test]
public void IEnumerable1Test_EnumeratorType ()
{
var myEnumerable = new NSMutableSet<NSNumber> ();
foreach (var item in myEnumerable) {
// The point of this test is to verify that the compiler finds the correct enumerator (the one returning NSNumbers, and not the one from the non-generic NSSet class returning NSObjects).
// This means that we don't have to actually execute this code, it's enough to make it compile.
Console.WriteLine (item.LongValue);
}
}
[Test]
public void IEnumerableTest ()
{

Просмотреть файл

@ -179,6 +179,17 @@ namespace MonoTouchFixtures.Foundation {
Assert.AreEqual (C, lst.Count, "iterator count");
}
[Test]
public void IEnumerable1Test_EnumeratorType ()
{
var myEnumerable = new NSOrderedSet<NSNumber> ();
foreach (var item in myEnumerable) {
// The point of this test is to verify that the compiler finds the correct enumerator (the one returning NSNumbers, and not the one from the non-generic NSSet class returning NSObjects).
// This means that we don't have to actually execute this code, it's enough to make it compile.
Console.WriteLine (item.LongValue);
}
}
[Test]
public void IEnumerableTest ()
{

Просмотреть файл

@ -165,6 +165,17 @@ namespace MonoTouchFixtures.Foundation {
}
}
[Test]
public void IEnumerable1Test_EnumeratorType ()
{
var myEnumerable = new NSSet<NSNumber> ();
foreach (var item in myEnumerable) {
// The point of this test is to verify that the compiler finds the correct enumerator (the one returning NSNumbers, and not the one from the non-generic NSSet class returning NSObjects).
// This means that we don't have to actually execute this code, it's enough to make it compile.
Console.WriteLine (item.LongValue);
}
}
[Test]
public void IEnumerableTest ()
{