-
-
Notifications
You must be signed in to change notification settings - Fork 580
Have IHtmlCollection<T> implement IReadOnlyList<T> #1227
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
Conversation
Sorry this would be breaking and is therefore not acceptable. Maybe we can have a non-breaking way (however, I doubt that - as I guess you explicitly want the interface to implement it). |
Why do you consider this a breaking change? It's not affecting any existing functionality. |
It changes a public interface. So if you upgrade your code will not compile (assuming you implement that interface somewhere). If you just swap you'll end up with an exception. So it requires changes which is by definition a breaking change. |
We could maybe overcome this with default interface implementation can't we? |
In general default interface methods could help (up to some extend), but as they require runtime support (starting with .NET Core 3.0, i.e., .NET standard 2.1) it would be another breaking change (see: https://github.com/AngleSharp/AngleSharp/blob/devel/src/AngleSharp.nuspec - it's .NET Standard 2.0 that we support in the lib). |
Would u consider target-specific implementation? public interface IHtmlCollection<T>
#if NET8_0_OR_GREATER
: IReadOnlyList<T>
#endif |
For example (all tests pass after changing only this file to the following): namespace AngleSharp.Dom;
using AngleSharp.Attributes;
using System;
using System.Collections.Generic;
/// <summary>
/// This type represents a set of space-separated tokens.
/// </summary>
[DomName("DOMTokenList")]
public interface ITokenList :
#if NET8_0_OR_GREATER
IReadOnlyList<String>
#else
IEnumerable<String>
#endif
{
/// <summary>
/// Gets the number of contained tokens.
/// </summary>
[DomName("length")]
Int32 Length { get; }
/// <summary>
/// Gets an item in the list by its index.
/// </summary>
/// <param name="index">The index of the item.</param>
/// <returns>The item at the specified index.</returns>
[DomName("item")]
[DomAccessor(Accessors.Getter)]
#if NET8_0_OR_GREATER
new
#endif
String this[Int32 index] { get; }
/// <summary>
/// Returns true if the underlying string contains a token, otherwise
/// false.
/// </summary>
/// <param name="token">The token to search for.</param>
/// <returns>The result of the search.</returns>
[DomName("contains")]
Boolean Contains(String token);
/// <summary>
/// Adds some tokens to the underlying string.
/// </summary>
/// <param name="tokens">A list of tokens to add.</param>
[DomName("add")]
void Add(params String[] tokens);
/// <summary>
/// Remove some tokens from the underlying string.
/// </summary>
/// <param name="tokens">A list of tokens to remove.</param>
[DomName("remove")]
void Remove(params String[] tokens);
/// <summary>
/// Removes the specified token from string and returns false.
/// If token doesn't exist it's added and the function returns true.
/// </summary>
/// <param name="token">The token to toggle.</param>
/// <param name="force"></param>
/// <returns>
/// True if the token has been added, otherwise false.
/// </returns>
[DomName("toggle")]
Boolean Toggle(String token, Boolean force = false);
#if NET8_0_OR_GREATER
Int32 IReadOnlyCollection<String>.Count => Length;
#endif
} |
I think it might be an option; but it definitely needs further testing (for instance the swap test; can the lib just be changed or is a re-compilation necessary; which also indicates a breaking change - this time not API, but ABI). |
I ran a manual test I created a new project with a project reference to AngleSharp.Core then replaced only the AngleSharp.Core.dll file with the output of the compilation containing the IReadOnlyList change |
Did the project contain a reference / a class defined to, e.g., implement |
Yes, it's a console app that adds a After replacing AngleSharp.dll in the console folder with the new one compiled after introducing the interface implementation change it still works as intended. |
Then let's do it :) |
FYI |
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 general I like it and I think we can go for it. However, I don't like that we need to hide the indexer using new
. That feels fishy. I know its rather a .NET problem, but my question is: Wouldn't we be able to use IReadOnlyCollection
instead of IReadOnlyList
, i.e., not using the indexer? What's your take - do you need the list / or would a collection be sufficient?
The reason we're 'overriding' it is to allow for the documentation and attributes. |
I know that. I have nothing against the reason; I have something against hiding and I'd like to avoid it (as written). |
Fixed |
Both systems are failing; any reason why you still use the list and not a collection? I don't really get it. As it stands the previous iteration was better imho. |
Bear with me just a bit more please flo 😁 BTW, I've learned a bit of the code in the CSS selector, a true masterpiece! |
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 like it with the abstract way. I think this is a great way to deal with it. Lets have this in the preview and let's recheck for breaking changes.
Types of Changes
Makes the
IHTmlCollection<T>
interface implementIReadOnlyList<T>
, which is the conventional interface for types that expose a count property and enables index access, features thatIHtmlCollection<T>
already provides.Closes #1226
Prerequisites
Please make sure you can check the following two boxes:
Contribution Type
What types of changes does your code introduce? Put an
x
in all the boxes that apply:Description
Upgrades
IHtmlCollection<T>
to implementIReadOnlyList<T>
instead of justIEnumerable<T>
since it already implements all its functionality.