-
Notifications
You must be signed in to change notification settings - Fork 983
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
Refactor SnapLines
to use IList
directly instead of casting to ArrayList
#10279
Conversation
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.
Changes in this file seem only stylistic. I root for them, but don't look like they belong to this PR
@elachlan As One idea here is to create a helper that allows us to force type safety internally: internal sealed class ListAdapter<T> : IList<T>
{
private readonly IList _list;
private ListAdapter(IList list) => _list = list.OrThrowIfNull();
T IList<T>.this[int index]
{
get => (T?)_list[index] ?? throw new InvalidOperationException();
set => _list[index] = value.OrThrowIfNull();
}
int ICollection<T>.Count => _list.Count;
bool ICollection<T>.IsReadOnly => _list.IsReadOnly;
void ICollection<T>.Add(T item) => _list.Add(item.OrThrowIfNull());
void ICollection<T>.Clear() => _list.Clear();
bool ICollection<T>.Contains(T item) => _list.Contains(item);
void ICollection<T>.CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
int IList<T>.IndexOf(T item) => _list.IndexOf(item);
void IList<T>.Insert(int index, T item) => _list.Insert(index, item.OrThrowIfNull());
void IList<T>.RemoveAt(int index) => _list.RemoveAt(index);
bool ICollection<T>.Remove(T item)
{
if (_list.IsReadOnly || !_list.Contains(item))
{
return false;
}
_list.Remove(item);
return true;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() => new Enumerator(_list.GetEnumerator());
private sealed class Enumerator(IEnumerator _enumerator) : IEnumerator<T>
{
T IEnumerator<T>.Current => (T)_enumerator.Current;
object IEnumerator.Current => _enumerator.Current;
void IDisposable.Dispose() { }
bool IEnumerator.MoveNext() => _enumerator.MoveNext();
void IEnumerator.Reset() => _enumerator.Reset();
}
public static IList<T> AsList(IList list) => list as IList<T> ?? new ListAdapter<T>(list);
} Then // Maybe we could make this public in the future? Naming would be quite a challenge I think.
internal IList<T> SnapLinesInternal => ListAdapter<SnapLines>.AsList(SnapLines);
// This is the _current_ SnapLinesInternal, which should be renamed.
internal IList<SnapLine> EdgeAndMarginSnapLines() => EdgeAndMarginSnapLines(Control.Margin); |
This submission has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 14 days. It will be closed if no further activity occurs within 7 days of this comment. |
I'll set aside some time and get the last changes sorted. |
f1c4eaf
to
6fdcd53
Compare
@JeremyKuhne I am not really following on how the |
@@ -1,8 +1,6 @@ | |||
// Licensed to the .NET Foundation under one or more agreements. | |||
// The .NET Foundation licenses this file to you under the MIT license. | |||
|
|||
#nullable disable |
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'm not sure annotating FlowPanelDesigner
for NRT should be part of this PR.
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.
Are you sure? Its a very small change.
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 though the parent class wasn't annotated, but apparently it is, so in that light it's a small change (though the parent's parent isn't, which exposes us to incorrect assumptions)
@elachlan |
@JeremyKuhne I think it clicked. Let me know if this makes sense. |
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.
Added some comments. Sorry about the delay, a bit busy currently.
|
||
using System.Collections; | ||
|
||
namespace System.Windows.Forms.Design; |
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.
Needs a blank line and comments for the class
@@ -93,7 +93,7 @@ public override IList SnapLines | |||
} | |||
} | |||
|
|||
return snapLines; | |||
return (IList)snapLines; |
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 won't work if the adapter is in play. One could add IList
to the adapter, but then everything would get the wrapper at that point. If they try to do the same thing again.
You can just not expose the internal and do the ListAdapter
call in each usage and return the original IList
. Another option is to create some internal interface that we could use as a general pattern to handle this sort of wrapping. Something like:
internal interface IWrapper<T>
{
T Unwrap();
}
internal ListAdapter<T> : IList<T>, IWrapper<IList>
{
IList IWrapper<IList>.Unwrap() => _list;
// ...
}
internal static AdapterHelpers
{
internal IList Unwrap(this IList list) => list is IWrapper<IList> wrapper ? wrapper.Unwrap() : (IList)list;
internal IList<T> Adapt(this IList list) => list is IList<T> ilist ? ilist : new ListWrapper(list);
}
// Example usage:
IList<SnapLine> snapLines = base.SnapLines.Adapt<SnapLine>();
// ...
return snapLines.Unwrap();
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 think this results in having to use List<SnapLine>
and not IList<SnapLine>
so as to avoid ((IList)snapLines).Unwrap();
// Example usage:
List<SnapLine> snapLines = base.SnapLines.Adapt<SnapLine>();
// ...
return snapLines.Unwrap();
Or should I just do the explicit cast?
828d48e
to
691af86
Compare
@elachlan this looks good outside of adding comments to the new types and making sure they are in individual files per guidelines. |
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.
Looks good, just get comments on the new types and move them into their own files.
@JeremyKuhne how is that? |
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.
Just one more nit
src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/AdapterHelpers.cs
Outdated
Show resolved
Hide resolved
Weird test failure I think is unrelated. |
Kind of related: #8140
Mostly trying to remove
ArrayList
usage through the code base. This code is using a typesafe cast toArrayList
, where it can just use IList directly.We cannot convert to
List<T>
because we have a public API that usesArrayList
ParentControlDesigner.AddPaddingSnapLines:winforms/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/ParentControlDesigner.cs
Lines 295 to 319 in cc1a968
Ultimately it would be great if the public API could be changed to
List<SnapLine>
to be more explicit.Microsoft Reviewers: Open in CodeFlow