Skip to content

Add Enum.Parse<T>() polyfill for .NET Framework builds (#5100)#5102

Merged
stevenaw merged 12 commits intonunit:mainfrom
shaig-mahmudov:feature/enum-parse-polyfill
Jan 12, 2026
Merged

Add Enum.Parse<T>() polyfill for .NET Framework builds (#5100)#5102
stevenaw merged 12 commits intonunit:mainfrom
shaig-mahmudov:feature/enum-parse-polyfill

Conversation

@shaig-mahmudov
Copy link
Contributor

@shaig-mahmudov shaig-mahmudov commented Jan 6, 2026

Added a generic Enum.Parse<T> polyfill in the NUnit.Compatibility namespace, wrapped in a #if NETFRAMEWORK conditional. This allows the framework to use the generic API on .NET Framework builds where it is not natively available. Closes #5100

@OsirisTerje
Copy link
Member

OsirisTerje commented Jan 6, 2026

If you run build and build --target test locally, you will get the same errors you see in the build log here locally. Makes it easier and faster to fix them.

Copy link
Member

@stevenaw stevenaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your interest and prompt PR @shaig-mahmudov.
I've left a few suggestions on how to adjust the code a bit which should allow this to seamlessly "just work".

Terje has also left a few suggestions on how to build and test this locally. There's a few build warnings (which you may be able to see in your IDE too) which are being escalated to errors by our CI build.


using System;

namespace NUnit.Compatibility
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a "miss" on my part in the original spec. There's ambiguity errors reported by the compiler. You can likely help make them go away by changing this namespace to System so that it matches the namespace of the built-in Enum type.

/// <typeparam name="T">The enum type to which to convert.</typeparam>
/// <param name="value">The string representation of the enumeration name or underlying value.</param>
/// <returns>An object of type T whose value is represented by value.</returns>
public static T Parse<T>(string value) where T : struct
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you convert this to use the C#14 extension member syntax then you can extend static methods onto Enum itself, similar to how we've added some of the classic asserts back onto the Assert class here: https://github.com/nunit/nunit/blob/main/src/NUnitFramework/nunit.framework.legacy/ClassicAssertExtensions.cs#L13-L19

Doing this will then allow you the update elsewhere in the code where we call Enum.Parse(typeof(EnumType), string) to instead call the generic Enum.Parse<EnumType>(string) method seamlessly

/// Provides a polyfill for the generic Enum.Parse{T} method which is available in
/// .NET Core and newer .NET versions but missing in .NET Framework.
/// </summary>
internal static class Enum
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend renaming this to EnumExtensions so that changing the namespace to System doesn't cause conflicts

Copy link
Contributor Author

@shaig-mahmudov shaig-mahmudov Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @stevenaw, I’ve applied the requested changes:
• Namespace: moved from NUnit.Compatibility to System to match the built-in Enum type and avoid ambiguity.
• Extension syntax: updated the implementation to use extension members so Enum.Parse() works seamlessly.
• Class name: renamed to EnumExtensions to avoid potential conflicts.
• Formatting: adjusted generic constraints (SA1127) to match the style guide.
• Local build: verified with dotnet build and dotnet build src/NUnitFramework/framework/nunit.framework.csproj across the relevant target frameworks.

Thanks for the guidance — happy to make further adjustments if needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shaig-mahmudov Look at the code @stevenaw linked to, or just see image below:
image

This is the new syntax, and then you get rid of the this Enum _ too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your changes @shaig-mahmudov

Terje is right about the new syntax as it will allow these methods to appear as if they are static methods on the built-in Enum class itself despite that they aren't "built-in" on .NET Framework. The goal behind a polyfill like this is to allow code to call a method on all runtimes we support even if it's only built into .NET itself on newer ones.

In other words, we'd want to also able to update these references within this PR:

To instead call

  • Enum.Parse<RuntimeType>(s, true)
  • Enum.Parse<InternalTraceLevel>((string)traceLevelValue, true)

As appropriate without needing any #if NETFRAMEWORK checks around where we call the method.

@shaig-mahmudov
Copy link
Contributor Author

@dotnet-policy-service agree

@shaig-mahmudov
Copy link
Contributor Author

shaig-mahmudov commented Jan 11, 2026

Hi @stevenaw, @TerjeP, I've updated the Enum.Parse polyfill as suggested:

  • Switched to the extension(Enum) syntax in EnumExtensions.cs.
  • Removed the this Enum _ parameter and updated the XML documentation.
  • Updated the calls in RuntimeFramework.cs and FrameworkController.cs to use the cleaner Enum.Parse(...) syntax.
  • Ready for another look. Thanks!"

@stevenaw
Copy link
Member

Thanks @shaig-mahmudov
The extension method itself looks as expected. Can you please check and see if you forgot to commit any other changes on your end? We'd like to update the calls in RuntimeFramework.cs and FrameworkController.cs where we use the old Enum.Parse() to instead call your new version so that it can be used :)

@shaig-mahmudov
Copy link
Contributor Author

@stevenaw Thanks for the feedback. I’ve updated the enum parsing in FrameworkController.cs and RuntimeFramework.cs to use the generic Enum.Parse<T>(..., true) syntax.

@stevenaw
Copy link
Member

Thanks @shaig-mahmudov ! Your changes look good, I appreciate your quick responses to each feedback.
I've pushed a few minor edits just to remove some extra periods in the xmldocs. A final build is running now and I'll merge upon its successful completion.

Thanks for your contribution!

@stevenaw stevenaw merged commit fb30e74 into nunit:main Jan 12, 2026
5 checks passed
@shaig-mahmudov
Copy link
Contributor Author

@stevenaw Thanks for the review, edits, and guidance! I appreciate it and I’m happy to contribute to the project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an Enum.Parse<T>() method for .NET Framework builds

3 participants