-
Notifications
You must be signed in to change notification settings - Fork 982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: implement generic IList interface #2749
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2749 +/- ##
==================================================
- Coverage 61.94595% 58.8531% -3.09285%
==================================================
Files 1256 1240 -16
Lines 447545 428861 -18684
Branches 39209 38934 -275
==================================================
- Hits 277236 252398 -24838
- Misses 164844 171122 +6278
+ Partials 5465 5341 -124
|
...stem.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabControl.TabPageCollectionTests.cs
Outdated
Show resolved
Hide resolved
using System.Diagnostics; | ||
|
||
namespace System.Windows.Forms | ||
{ | ||
public class ArraySubsetEnumerator : IEnumerator | ||
public class ArraySubsetEnumerator<T> : IEnumerator<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this may look like a major breaking change it isn't, the class previously was internal and mistakenly was made public in a recent refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed it as well:
winforms/src/System.Windows.Forms/src/PublicAPI.Unshipped.txt
Lines 1 to 5 in ad8ff38
System.Windows.Forms.ArraySubsetEnumerator | |
System.Windows.Forms.ArraySubsetEnumerator.ArraySubsetEnumerator(object[] array, int count) -> void | |
System.Windows.Forms.ArraySubsetEnumerator.Current.get -> object | |
System.Windows.Forms.ArraySubsetEnumerator.MoveNext() -> bool | |
System.Windows.Forms.ArraySubsetEnumerator.Reset() -> void |
We need to make it internal
again.
c2343d0
to
3e827a3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This iteration tries to limit signature changes to GetEnumerator
methods to see whats required to enable foreach
picking up the generic signature. Turns out a few classes have problems with that because their GetEnumerator
is virtual.
public void Remove(string value) => TryRemove(value); | ||
|
||
bool ICollection<string>.Remove(string value) => TryRemove(value); | ||
|
||
private bool TryRemove(string value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this PR iteration instead of changing return type of public Remove
methods I instead add a private TryRemove
method to avoid code duplication so that interfaces can use the same call.
{ | ||
int[] indices = new int[Count]; | ||
CopyTo(indices, 0); | ||
return indices.GetEnumerator(); | ||
return WindowsFormsUtils.GetArrayEnumerator(indices); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting the generic IEnumerator<>
from an array requires casting the array, going through a helper function to avoid getting the cast wrong. If you prefer inlined casts I can of course remove this helper function.
public new virtual IEnumerator<Control> GetEnumerator() | ||
{ | ||
return new ControlCollectionEnumerator(this); | ||
} | ||
|
||
protected override IEnumerator GetEnumeratorCore() | ||
{ | ||
return GetEnumerator(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an attempt to enable foreach
picking up the generic enumerator, if you have better suggestions I'm open to try them out.
This particular attempt is adding a second virtual mehtod GetEnumeratorCore
on the base class so subclasses can both override and shadow the GetEnumerator
method at the same time. Alternatives which do less contortions (e.g. adding a generic parameter to the base class or changing how GetEnumerator is exposed on the base class) would probably be even more breaking to the subclass hierarchy. Since for now we want to explore solutions with minimum breaking changes while still getting the advantages of foreach signatures I chose to explore above workaround.
@@ -536,6 +536,7 @@ public void ColumnHeaderCollection_Clear_Empty_Success() | |||
} | |||
|
|||
[Fact] | |||
[Diagnostics.CodeAnalysis.SuppressMessage("Assertions", "xUnit2017:Do not use Contains() to check if a value exists in a collection", Justification = "We are testing the Contains method itself")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you prefer #pragma warning disable
over attributes? Can update if desired.
@@ -15,7 +15,7 @@ public class BindingsCollectionTests : IClassFixture<ThreadExceptionFixture> | |||
public void Ctor_Default() | |||
{ | |||
var collection = new SubBindingsCollection(); | |||
Assert.Equal(0, collection.Count); | |||
Assert.Empty(collection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are not testing the Count
property explicitely so I followed the xunit analyzer and updated the call
3e827a3
to
df05a6d
Compare
Closing PR, changing |
Contributes to #2644
Alternative implementation to PR #2999
This is a WIP PR for exploring the impact #2644 may have and whether its worth taking the breaking change.
This PR contains adding
IList<T>
interface implementation to types currently implementingIList
. I thought it'd be a good way to start the work. If you want me to split down further in either multiple commits or separate PRs I don't mind, I fully expect having to go through the full changes several times anyways. On that note, if you have nits don't bother reviewing/annotating all of them, just pick one representative for discussion.Notes:
IList
methods (where available), this makes for weird placement since not allIList<T>
methods are together, but considering I don't really want to reorder the existing methods (unless asked to) I figured it'd be the best solution to minimize diffs for now.ArrayList
) to their subclasses. Should we break subclasses by changing the type of the backing list to a generic collection? Nullability annotations would profit from such a change.Remove
implementations don't tell the caller whether they removed something, butIList<T>
requires this in its API. I've updated them where it looked sensible but someRemove
implementations are virtual and changing return type tobool
would require updating subclasses. I opted to not do this in this PR before discussing this point, instead for now I did implementIList<T>.Remove
as explicit interface with a weird workaround. That is just placeholder until it is clear what is desired.Remove
implementations whether the item to be removed is actually part of the collection. They run logic which severs the item and partially disconnects it from its true owner, but without notifying that owner. I did not fix these bugs yet (some are marked with comments though), I'm going to create a separate issue for this problem (so it doesn't have to wait for this issue/PR, which probably will take a while to dicscuss and resolve all points).Assert.Contains
orAssert.DoesNotContain
. Minor inconvenience which is easily fixed.Microsoft Reviewers: Open in CodeFlow