Skip to content
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

Private enumeration type can not be recognized when converted to dynamic #79045

Open
anranruye opened this issue Nov 30, 2022 · 4 comments
Open
Labels
area-Microsoft.CSharp untriaged New issue has not been triaged by the area owner

Comments

@anranruye
Copy link

Description

Consider that we want to build a common method to perform | (bitwise or) operation for any enumeration type.
The simplest way could be converting the enum value to dynamic:

    class HelperClass
    {
        // notice that the constraint here doesn't help to allow bitwise operator, still need to use dynamic keyword
        public static T BitwiseOr<T>(T a, T b) where T : Enum
        {
            return (dynamic)a | (dynamic)b;
        }
    }

This works well when the enum type is visible for HelperClass, but if the enum tupe is private, then the dynamic bitwise operation fails.

internal class Program
    {
        public static void Main(string[] args)
        {
            MyEnum1 a1 = MyEnum1.A;
            MyEnum1 b1 = MyEnum1.B;
            MyEnum2 a2 = MyEnum2.A;
            MyEnum2 b2 = MyEnum2.B;
            HelperClass.PrintType<MyEnum1>();
            HelperClass.PrintType<MyEnum2>(); // can get the full name of MyEnum2 type
            Console.WriteLine(HelperClass.BitwiseOr(a1, b1)); // ok
            Console.WriteLine(HelperClass.BitwiseOr(a2, b2)); // failed
        }

        public enum MyEnum1 : int
        {
            A = 1,
            B = 2,
            C = 4,
        }

        enum MyEnum2 : int
        {
            A = 1,
            B = 2,
            C = 4,
        }
    }

    class HelperClass
    {
        public static T BitwiseOr<T>(T a, T b) where T : Enum
        {
            return (dynamic)a | (dynamic)b;
        }

        public static void PrintType<T>()
        {
            Console.WriteLine(typeof(T));
        }
    }

Reproduction Steps

run the code above

Expected behavior

no excetion throwed

Actual behavior

Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Operator '|' cannot be applied to operands of type 'System.Enum' and 'System.Enum'

Regression?

No response

Known Workarounds

use lambda expression to dynamiclly build a method for each enum type. This method converts the enum values to underlying numeric type, do bitwise operation, then converts the numeric value back to enum value.

This approach is complex and need advanced skills for the developer to implement.

Configuration

.NET 7
Windows 11
x64
I don't think so

Other information

No response

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Nov 30, 2022
@ghost
Copy link

ghost commented Nov 30, 2022

Tagging subscribers to this area: @cston
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

Consider that we want to build a common method to perform | (bitwise or) operation for any enumeration type.
The simplest way could be converting the enum value to dynamic:

    class HelperClass
    {
        // notice that the constraint here doesn't help to allow bitwise operator, still need to use dynamic keyword
        public static T BitwiseOr<T>(T a, T b) where T : Enum
        {
            return (dynamic)a | (dynamic)b;
        }
    }

This works well when the enum type is visible for HelperClass, but if the enum tupe is private, then the dynamic bitwise operation fails.

internal class Program
    {
        public static void Main(string[] args)
        {
            MyEnum1 a1 = MyEnum1.A;
            MyEnum1 b1 = MyEnum1.B;
            MyEnum2 a2 = MyEnum2.A;
            MyEnum2 b2 = MyEnum2.B;
            HelperClass.PrintType<MyEnum1>();
            HelperClass.PrintType<MyEnum2>(); // can get the full name of MyEnum2 type
            Console.WriteLine(HelperClass.BitwiseOr(a1, b1)); // ok
            Console.WriteLine(HelperClass.BitwiseOr(a2, b2)); // failed
        }

        public enum MyEnum1 : int
        {
            A = 1,
            B = 2,
            C = 4,
        }

        enum MyEnum2 : int
        {
            A = 1,
            B = 2,
            C = 4,
        }
    }

    class HelperClass
    {
        public static T BitwiseOr<T>(T a, T b) where T : Enum
        {
            return (dynamic)a | (dynamic)b;
        }

        public static void PrintType<T>()
        {
            Console.WriteLine(typeof(T));
        }
    }

Reproduction Steps

run the code above

Expected behavior

no excetion throwed

Actual behavior

Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Operator '|' cannot be applied to operands of type 'System.Enum' and 'System.Enum'

Regression?

No response

Known Workarounds

use lambda expression to dynamiclly build a method for each enum type. This method converts the enum values to underlying numeric type, do bitwise operation, then converts the numeric value back to enum value.

This approach is complex and need advanced skills for the developer to implement.

Configuration

.NET 7
Windows 11
x64
I don't think so

Other information

No response

Author: anranruye
Assignees: -
Labels:

area-Microsoft.CSharp, untriaged

Milestone: -

@cston
Copy link
Member

cston commented Dec 16, 2022

@anranruye, thanks for reporting this issue and for providing a clear repro.

It looks like this is existing behavior (rather than a regression) since the behavior is the same with .NET Framework 4.7.2.

Unfortunately, the Microsoft.CSharp library is effectively archived, and we are only taking changes that address significant bugs or regressions, or changes needed to continue shipping - see README.md.

@anranruye
Copy link
Author

anranruye commented Dec 22, 2022

@cston then how about considering Enum type implicitly as IBitwiseOperators<T, T, T>? which makes where T : Enum or where T : IBitwiseOperators<T, T, T> help in this scenario. See dotnet/csharplang#6761.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Microsoft.CSharp untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

3 participants