Skip to content

[API Proposal]: Type.GetEnumValuesAsUnderlyingType #72498

Closed

Description

@MichalStrehovsky

Background and motivation

The existing Type.GetEnumValues API returns a System.Array that is of the given enum type (i.e. SomeEnum[] when called on typeof(SomeEnum)). This makes implementing the API challenging when the enum array cannot be created. There are multiple reasons why the enum array might not be possible to create:

  1. We're in a reflection-only context such as MetadataLoadContext:
    public sealed override Array GetEnumValues() => throw new InvalidOperationException(SR.Arg_InvalidOperation_Reflection);
  2. We're on a platform where runtime codegen (or universal shared code) is not available.

It would be good to have API that can work in these contexts by returning an array of the underlying type (i.e. int[] for typeof(SomeInt32Enum).

API Proposal

namespace System;

public abstract class Type
{
    public virtual Array GetEnumValuesAsUnderlyingType();
}

API Usage

foreach (var value in typeof(SomeEnum).GetEnumValuesAsUnderlyingType())
    Console.WriteLine(value);

// Prints:
// 0
// 1
//
// As opposed to:
//
// SomeEnumValue1
// SomeEnumValue2

Alternative Designs

Allow implementers to not satisfy the contract

The implementation of the existing Type.GetEnumValues could just return the underlying array directly since the signature is just System.Array. But that is probably pretty breaking - see #72236 (comment) for samples.

Write more code

Can be expressed in a less performant and more verbose way already:

foreach (var f in typeof(DayOfWeek).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
{
    Console.WriteLine(f.Name);
    Console.WriteLine(f.GetRawConstantValue()); // This returns the field value as boxed underlying type
}

Risks

No response

Activity

  1. added
    blockingMarks issues that we want to fast track in order to unblock other important work
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on Jul 19, 2022
  2. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Jul 19, 2022
  3. MichalPetryka commented on Jul 20, 2022

    @MichalPetryka
    Contributor

    Would this API return an array of the underlying type in all cases or only when it's not possible to figure out the type under AOT?

  4. MichalStrehovsky commented on Jul 20, 2022

    @MichalStrehovsky
    MemberAuthor

    Would this API return an array of the underlying type in all cases or only when it's not possible to figure out the type under AOT?

    In all cases. Switching the array type around would be a compat problem in the same sense as returning int[] from the existing API. No reason to introduce it.

  5. MichalPetryka commented on Jul 20, 2022

    @MichalPetryka
    Contributor

    Does it make more sense to have the API on Type or in Enum? Currently APIs are in both of those places.

  6. MichalStrehovsky commented on Jul 20, 2022

    @MichalStrehovsky
    MemberAuthor

    For the MetadataLoadContext use case, the Type API is the one that makes sense.

    I'll leave it up to the API review board whether it makes sense to add a shortcut on Enum for discoverability.

  7. GrabYourPitchforks commented on Jul 20, 2022

    @GrabYourPitchforks
    Member

    @MichalStrehovsky This is marked blocking. Be sure to add a milestone (7.0 or Future) as well. Thanks!

  8. added this to the 7.0.0 milestone on Jul 20, 2022
  9. ghost removed
    untriagedNew issue has not been triaged by the area owner
    on Jul 20, 2022
  10. MichalStrehovsky commented on Jul 20, 2022

    @MichalStrehovsky
    MemberAuthor

    @MichalStrehovsky This is marked blocking. Be sure to add a milestone (7.0 or Future) as well. Thanks!

    Marked for 7.0, thanks for spotting!

  11. marek-safar commented on Jul 22, 2022

    @marek-safar
    Contributor
  12. terrajobst commented on Jul 26, 2022

    @terrajobst
    Contributor

    Video

    • Let's add a corresponding method on Enum as this would maintain the parity with the existing methods that exist on both Type and Enum.
    • Let's also add a generic version for parity
    namespace System;
    
    public partial class Type
    {
        // Existing enum related methods:
        //
        // public virtual string? GetEnumName(Object);
        // public virtual string[] GetEnumNames();
        // public virtual Type GetEnumUnderlyingType();
        // public virtual object[] GetEnumValues();
    
        public virtual Array GetEnumValuesAsUnderlyingType();
    }
    
    public partial class Enum
    {
        public static Array GetValuesAsUnderlyingType<TEnum>() where TEnum: struct, Enum;
        public static Array GetValuesAsUnderlyingType(Type type);
    }
  13. added
    api-approvedAPI was approved in API review, it can be implemented
    and removed
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on Jul 26, 2022
  14. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Jul 29, 2022
  15. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Aug 2, 2022
  16. ghost locked as resolved and limited conversation to collaborators on Sep 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-System.ReflectionblockingMarks issues that we want to fast track in order to unblock other important work

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions