tylerbrinkley / enums.net Goto Github PK
View Code? Open in Web Editor NEWEnums.NET is a high-performance type-safe .NET enum utility library
License: MIT License
Enums.NET is a high-performance type-safe .NET enum utility library
License: MIT License
I tried to write a simple converter between two very similar enums (partially auto generated ones) based on the name, but got stuck quite a bit. Looks like I would need to reimplement a lot of your code to get it to work.
Here is what I wanted to build (without the constraints):
public static TEnumResult ConvertByName<TEnum, TEnumResult>(TEnum e, TEnumResult defaultValue)
{
TEnumResult result;
if (!Enums.TryParse(e.AsString(EnumFormat.Name), true, out result))
{
return defaultValue;
}
return result;
}
enum NumericOperator
{
[Symbol("==","C#")]
[Symbol("=","F#")]
Equals,
[Symbol("NotEquals")]
[Symbol("!=","C#")]
[Symbol("<>","F#")]
NotEquals,
[Symbol(">")]
Greater,
}
And I get can ==
by passing C#
key and =
by passing F#
key and Equals
with no key from Equals enum value?
And I get can >
by passing C#
key or by F#
key or no key from Greater enum value?
It may be used during serialization into several databases. E.g. same enum stored into SQL database and into search database and into analytics database.
Hi, I just found your lib, lifesaver!! 👍 I am trying to replace the traditional Enum with your lib..
I'm outside a for/foreach loop, and would like to increment
an Enum for e.g Submitted
to Approved
how could I move through the enums
Document.Status.Next() // success/true, if false it was the last enum.
Document.Status.NextOrLast() //
Document.Status.Previous() //
Document.Status.PreviousOrFirst() //
Can I set a status from string, Document.Status = "Approved";
?
thanks
Hi Tyler,
Been watching this for a while and I hope it finally gets included as it is a great addition to .NET IMHO.
I am in the process of converting my (simple) enum helper and have the following that I don't know how to convert:
/// <summary>
/// Class to assist with manipulating enums. These operate on the enum type as a whole and
/// are hence not extension methods for the enum members themselves.
/// </summary>
/// <typeparam name="T">Enumeration we are operating on.</typeparam>
public static class SpYtEnumHelper<T> where T : struct, IConvertible
{
/// <summary>
/// Internal helper method to ensure that the type we are dealing with is an enumeration.
/// </summary>
/// <returns>
/// Returns the type information for the enumeration. Raises an exception if the type supplied is not an
/// enumeration.
/// </returns>
private static Type CheckIsEnum()
{
Type result = typeof(T);
if (!result.IsEnum) throw new Exception("T must be an Enumeration type.");
return result;
}
/// <summary>
/// Given the ordinal position of the member within the enumeration we return the enum member.
/// </summary>
/// <param name="aOrdinalPosition">Zero based position of the member within the enumeration.</param>
/// <returns>Returns the enumeration member if found.</returns>
/// ///
/// <remarks>With an enum of MyEnum {Red = 3, Green = 5, Orange = 12} => GetMemberFromOrdinalPosition(1) = Green. </remarks>
public static T GetMemberFromOrdinalPosition(int aOrdinalPosition)
{
Type enumType = CheckIsEnum();
return (T) Enum.Parse(enumType, Enum.GetNames(typeof(T))[aOrdinalPosition]);
}
}
So given:
enum NumericOperator
{
[Symbol("="), Description("Is")]
Equals = 2,
[Symbol("!="), Description("Is not")]
NotEquals,
[Symbol("<")]
LessThan,
[Symbol(">="), PrimaryEnumMember] // PrimaryEnumMember indicates enum member as primary duplicate for extension methods
GreaterThanOrEquals,
NotLessThan = GreaterThanOrEquals,
[Symbol(">")]
GreaterThan,
[Symbol("<="), PrimaryEnumMember]
LessThanOrEquals,
NotGreaterThan = LessThanOrEquals
}
/// <summary>
/// Tests for SpYtEnumHelper.
/// </summary>
[TestFixture]
public class SpYtEnumHelperTests : SpYtTestsBase
{
[Test]
public void DummyTest()
{
//GetMemberFromValue
SpYtEnumHelper<NumericOperator>.GetMemberFromValue(3).ShouldBe(NumericOperator.NotEquals);
Enums.GetMember<NumericOperator>("3", EnumFormat.DecimalValue).Value.ShouldBe(SpYtEnumHelper<NumericOperator>.GetMemberFromValue(3));
//GetMemberFromOrdinalPosition
SpYtEnumHelper<NumericOperator>.GetMemberFromOrdinalPosition(0).ShouldBe(NumericOperator.Equals);
//Enums.GetMember<NumericOperator>("0", EnumFormat.EnumMemberValue).Value.ShouldBe(SpYtEnumHelper<NumericOperator>.GetMemberFromOrdinalPosition(0));
//Enums.GetMember<NumericOperator>("0", EnumFormat.UnderlyingValue).Value.ShouldBe(SpYtEnumHelper<NumericOperator>.GetMemberFromOrdinalPosition(0));
}
}
I am looking for the equivalence of my GetMemberFromOrdinalPosition()
but none of the EnumFormat
members appear to do that. While I realise I could do:
Enums.GetMembers<NumericOperator>().Skip(0).First().Value
I was hoping there was something more elegant I had missed?
The call to .AsString() can get completely stuck (likely infinite loop inside) on certain inputs.
The code below will repro the issue. Tested on both net462 an net6.0 and with both V4.0.1.
Attaching zip with SLN that includes a single project with a single Program.cs containing the code below.
Program.cs:
using System;
using System.Diagnostics;
using EnumsNET;
public class Program
{
public static void Main(string[] args)
{
MyEnum value = MyEnum.Val1 | MyEnum.Val30;
Trace.WriteLine($"{(int)value}"); // <-- Works
Trace.WriteLine($"{(MyEnum)((int)value)}"); // <-- Works
Trace.WriteLine($"{value}"); // <-- Works
Trace.WriteLine($"{value.AsString()}"); // <-- Stuck :(
}
[Flags]
public enum MyEnum
{
Invalid = 0,
Val1 = 1 << 0,
Val30 = 1 << 30,
}
}
The Csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net462</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Enums.NET" Version="4.0.1" />
</ItemGroup>
</Project>
Hello! Is it possible to provide an explicit use of EnumInfo<,,> and it's constructor, instead of implicit Activator.CreateInstance?
We use your library in our Unity project, which use AOT compilation and compiler can't determine using of EnumInfo<,,> type.
In result code doesn't generated for type and we catch exceptions in runtime.
The changes made in #15 seem to mean that Enums.NET 2.3.0
cannot run on netstandard1.6
, even though Enums.NET
targets netstandard1.0
+.
https://www.nuget.org/packages/Enums.NET/2.3.0
On dotnet restore
, I get the following:
> dotnet restore
Restoring packages for C:\<--snip-->\HttpDownloader\HttpDownloader.csproj...
C:\<--snip-->\HttpDownloader\HttpDownloader.csproj : error NU1605: Detected package downgrade: NETStandard.Library from 2.0.0 to 1.6.1. Reference the package directly from the project to select a different version.
C:\<--snip-->\HttpDownloader\HttpDownloader.csproj : error NU1605: HttpDownloader -> Enums.NET 2.3.0 -> NETStandard.Library (>= 2.0.0)
C:\<--snip-->\HttpDownloader\HttpDownloader.csproj : error NU1605: HttpDownloader -> NETStandard.Library (>= 1.6.1)
Restore failed in 193,86 ms for C:\<--snip-->\HttpDownloader\HttpDownloader.csproj.
When creating this library, I deliberately tried to make the API and behavior as close to System.Enum
's as possible in order for it to be a drop in replacement as well as allowing Enums.NET
to be the basis for improvements to System.Enum
in corefx as has been proposed with corefx#15453.
There are however a few behavioral differences that either snuck in or were made deliberately. If corefx#15453 gets implemented I will like to update Enums.NET
to a new major version which fixes most of these behavioral differences.
API | Enums.NET Behavior |
System.Enum Behavior |
Proposed Solution |
---|---|---|---|
GetNames |
Names are returned in increasing order by their respective values | Names are returned in increasing significance bit order by their respective values | Add an EnumMemberSelection.ValueOrder flag enum member |
GetValues |
Values are returned in increasing value order | Values are returned in increasing significance bit order | Add an EnumMemberSelection.ValueOrder flag enum member |
GetMembers |
Members are returned in increasing order by their respective values | Members will be returned in increasing significance bit order by their respective values | Add an EnumMemberSelection.ValueOrder flag enum member |
ToObject |
Throws OverflowException when value is outside the underlying type's value range |
Allows overflowing values | Rework EnumValidation enum and add an EnumValidation.NoOverflow flag enum member. EnumValidation.None , EnumValidation.IsDefined , and EnumValidation.IsValidFlagCombination will have new meanings such that they no longer validate there were no overflows. |
AsString and Format with flags |
For flags, if the value is not defined then each of it's individual flags are output | For flags, the defined combinations within the value with the largest values are output until their are no more flags left to output | Hard break in Enums.NET . To get the same behavior as before you'll need to replace it with something like this. value.IsValidFlagCombination() ? string.Join(", ", value.GetFlagMembers().Select(flag => flag.Name) : value.AsString() |
Additionally, more research must be done to determine the behavioral differences for the following methods with their accepted value types and the exceptions they throw.
Format(Type enumType, object value, string format)
GetName(Type enumType, object value)
IsDefined(Type enumType, object value)
EnumsNET.PrimaryEnumMemberAttribute
to System.ComponentModel.PrimaryAttribute
.System.ComponentModel.AttributeCollection
and then add appropriate extension methods to support the existing methods on EnumsNET.AttributeCollection
in older versions of System.ComponentModel.AttributeCollection
. This will mean in older framework targets the attribute collection will not explicitly implement IList<Attribute>
or IReadOnlyList<Attribute>
as is currently the case but will support being casted to those interfaces as the returned attribute collection will derive from System.ComponentModel.AttributeCollection
for older framework targets.GetAllFlags
to AllFlags
as in the proposal.IsValidFlagCombination
will be promoted to an extension method in older framework targets.EnumMember
in newer framework targets that already contain the built-in EnumMember
and use that instead.Does Enums.NET
enable the use of an enum as a type parameter?
If so, what would be the proper usage syntax?
Both the "generic" enum.GetFlags() and non-generic version of GetFlags(Type enumType, object value) get completely stuck (likely infinite loop inside) on certain inputs.
The GetFlags method returns but either enumerating the input or using random access (flags[0]) will cause execution to get stuck.
The code below will repro the issue. Tested on both net462 an net6.0 and with both V3.0.3 and V4.0.0.
Attaching zip with SLN that includes a single project with a single Program.cs containing the code below.
public static void Main(string[] args)
{
MyEnum value = (MyEnum)1610612801;
var flags = value.GetFlags();
Trace.WriteLine($"{string.Join(",", flags)}"); // <-- This is stuck during enumeration of flags
var flags2 = FlagEnums.GetFlags(typeof(MyEnum), value);
Trace.WriteLine($"{string.Join(",", flags2)}"); // <-- This is stuck during enumeration of flags
}
[Flags]
public enum MyEnum
{
Unknown = 0x0,
Val1 = 0x1,
Val4 = 0x4,
Val8 = 0x8,
Val10 = 0x10,
Val20 0 = 0x40,
Val80 = 0x80,
}
Tried cloning repo and running tests locally and ran into these errors:
The type or namespace name 'BooleanEnum' could not be found (are you missing a using directive or an assembly reference?)
The type or namespace name 'CharEnum' could not be found (are you missing a using directive or an assembly reference?)
They are present in a good bit of the test code, for example in file EnumsTest.cs:
public void GetUnderlyingType()
{
Assert.AreEqual(typeof(sbyte), GetUnderlyingType<SByteEnum>());
Assert.AreEqual(typeof(byte), GetUnderlyingType<ByteEnum>());
Assert.AreEqual(typeof(short), GetUnderlyingType<Int16Enum>());
Assert.AreEqual(typeof(ushort), GetUnderlyingType<UInt16Enum>());
Assert.AreEqual(typeof(int), GetUnderlyingType<Int32Enum>());
Assert.AreEqual(typeof(uint), GetUnderlyingType<UInt32Enum>());
Assert.AreEqual(typeof(long), GetUnderlyingType<Int64Enum>());
Assert.AreEqual(typeof(ulong), GetUnderlyingType<UInt64Enum>());
Assert.AreEqual(typeof(bool), GetUnderlyingType<BooleanEnum>()); <<<
Assert.AreEqual(typeof(char), GetUnderlyingType<CharEnum>()); <<<
}
I noticed that they were removed in this commit 63a0467 . Should they be re-implemented, or should the tests be updated to no longer reference them? Wanted to raise some awareness on this.
Instead of relying on the params
for when there are 3 EnumFormat
s or less it'd be nice to have explicit overloads for those cases so as not to require creation of an array for performance reasons.
Apologies, might be machine, but I cannot build this project.
Download, run runbuild.cmd but always get this error (below)
I tried running nuget console: Update-Package –reinstall
Seems to update the right package.
Still doesn't fix it.
Could be my machine or the wonder of NuGet but I've had to give up.
C:\code\Enums.NET\Working\Src\Enums.NET\Enums.NET.csproj(93,5): error : This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is ..\packages\Fody.1.29.4\build\dotnet\Fody.targets.
You write "There is currently no way to constrain a type or method's generic type parameter to an enum in C#.".
Please consider this useful technique before saying it isn't possible.
Here are some of the major changes for the 3.0 release.
ReadOnlySpan<char>
parsing support when targeting .NET Core 3.0+.GetNames
, GetValues
, GetMembers
, GetFlags
, and GetFlagMembers
now all return an IReadOnlyList<T>
instead of IEnumerable<T>
.IReadOnlyList<T>
was added in .NET Framework 4.5, support for prior .NET Framework versions has been removed.System.Runtime.CompilerServices.Unsafe
package for efficient conversions between the enum and its underlying type instead of relying on Fody to implement that.System.Runtime.CompilerServices.Unsafe
package.NonGenericEnums
, NonGenericFlagEnums
, UnsafeEnums
, and UnsafeFlagEnums
are now deprecated and will be removed in v4.0. The equivalent methods have been added to the Enums
and FlagEnums
classes with the unsafe versions having the suffix of Unsafe
to avoid a naming conflict with the type-safe versions. This was done to better match System.Enum
and provide better discoverability being more centralized. I've created the C# roslyn analyzer Enums.NET.Analyzer
which provides an easy way to migrate your usages of the non-generic and unsafe methods to the new locations.NonGenericEnums
and NonGenericFlagEnums
.As well we have IsDefined
and IsValid
, would be nice to have the IsObsolete
extension method.
I missed it today.
May I open a PR for this?
Prototype:
public static bool IsObsolete<TEnum>(this TEnum value)
where TEnum : struct, Enum
{
return typeof(TEnum)
.GetField(value.ToString())
.GetCustomAttributes(typeof(ObsoleteAttribute), false)
?.Length > 0;
}
Hi,
would you be willing to add support for parsing ReadOnlySpan any time soon ?
This looks like a very useful and interesting library. I've been going through the test cases to see if a particular bit of functionality might be in the library... but alas couldn't see it in there.
What I'm hoping to find is an extension method to verify that an composite enum (bitwise ORing of multiple enum values) has One and only One member value of a specified Type. Let me paint a picture of what I'm doing. I'm utilizing several enums to represent ingredients and size attributes of a pizza like so:
public class Pizza
{
enum pizzaSize
{
small,
medium,
large
}
[Flags]
enum cheeseTopping
{
None = 0,
MozzerrellaX1 = 1, // normal amount of cheese
MozzerrellaX2 = 2, // double the amount of cheese
MozzerrellaX3 = 4 // three times the amount of cheese
}
[Flags]
enum pepperoniTopping
{
None = 0,
PepperoniX1 = 8, //normal amount of pepperoni
PepperoniX2 = 16, // double the amount of pepperoni
PepperoniX3 = 32 // three times the amount of pepperoni
}
[Flags]
enum menuItems
{
smallCheeseOnlyPizza = pizzaSize.small | cheeseTopping.MozzerrellaX1,
smallDoubleCheeseOnlyPizza = pizzaSize.small | cheeseTopping.MozzerrellaX2
largeMegaPepperoniAndHumongousCheesePizza = pizzaSize.large | cheeseTopping.MozzerrellaX3 | pepperoniTopping.PepperoniX3
}
}
Now what I'm trying to achieve in a pizza-order validation method is to ensure that for each enum type [cheeseTopping, pepperoniTopping, etc.], there can only be ONE member type selected (ie. either PepperoniX1, PepperoniX2 or PepperoniX3, but not two of them or all three of them in the menuItems.largeMegaPepperoniAndHumongousCheesePizza composite enum). In other words... you only can have one of each enum member values for each ingredient in your pizza.
Can this be easily done using this library or is it something that could be added relatively easily?
One other quick question... when using [Flags], I understand that the maximum number of member enums which are assigned values using [Flags] in the class is limited because the values are hard-coded sized as int32 by design (thus I think you can have 127 members, thus a max value of 2^127 as maximum the int32 value). Does your library increase this range by chance... to use perhaps a ulong (64bit) so that you could have vastly more [Flags]-based enums in the class)? I just don't like the limitations imposed. I really want ALOT of toppings :)
Thanks.
Regards,
Mark Chipman
Always looking for the impossible, I found myself in need of the following:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
internal class AliasAttribute : Attribute
{
public AliasAttribute(string text) => Text = text;
public string Text { get; set; }
}
public enum Direction
{
[Alias("^")]
[Alias("N")]
North,
[Alias("v")]
[Alias("S")]
South
}
var aliasFormat = Enums.RegisterCustomEnumFormat(x => x.Attributes.Get<AliasAttribute>()?.Text);
var direction = Enums.Parse<Direction>("N", ignoreCase: true, aliasFormat);
The above fails with "'string was not recognized as being a member of Direction (Parameter 'value')'" because it will only work with the value of the first attribute on each field. I'm wondering whether I'm missing a clever trick with the Enums.RegisterCustomEnumFormat
command. But even with a single refactored AliasAttribute
per field that could store multiple values (eg. [Alias("N", "^")]
), I wouldn't know how to achieve my goal...
I switched over to EnumsNET from my quickly made util class due to frustration of implementing what I wanted out of it when it already existed here all this time and more. The one thing I miss however is a means of enumerating the values of an enum without memory allocation. Is it possible to include this feature in some way?
Your point #3 on README.md says "It's all, by the way."
This is incorrect.
[Flags]
public enum EnumValue {
One = 0x01,
Two = 0x02,
Four = 0x04,
}
private static void CheckEnum() {
EnumValue twoAndFour = EnumValue.Two | EnumValue.Four;
Console.WriteLine("{0}", twoAndFour.HasFlag(EnumValue.One));
Console.WriteLine("{0}", twoAndFour.HasFlag(EnumValue.Two));
Console.WriteLine("{0}", twoAndFour.HasFlag(EnumValue.Four));
Console.WriteLine("{0}", twoAndFour.HasFlag(EnumValue.Two | EnumValue.Four));
}
False
True
True
True
All the more reason for the unclear default to crash and burn, of course. I'd recommend checking out https://github.com/LazyBui/EnumLib/blob/master/Enum%20Problems.md for some more stuff you might not have considered.
No doubt this is my fault, with some other config
But I had to roll back Enums.NET v3 to avoid getting this runtime error - only when running tests.
Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
at System.Runtime.CompilerServices.UnsafeUtility.As[TFrom,TTo](TFrom& source)
at EnumsNET.Enums.GetName[TEnum](TEnum value) in C:\Users\tydud\source\repos\TylerBrinkley\Enums.NET\Src\Enums.NET\Enums.cs:line 963
I haven't tried this out yet, but it looks really good. I came across the library when researching enums as generic constraints. Another area where enums aren't supported well by the framework is in attribute parameters. Does this library help in that area? If not, is that something that could be added?
See: https://codereview.stackexchange.com/questions/201807/int-to-enum-extension-method
Does Enums.NET address this? If not, is is possible to add it?
Hello, I ran into this problem.
I am using your lib., where I have a VM with enum fields, and when try to copy that over to a model using implicit (or other function or any copy ocnstructor) I get the error "Values of enumerated types decorated with the FlagsAttribute can not be converted to string."
So I found this to be a common issue, and sol
public static IEnumerable<T> GetUniqueFlags<T>(this Enum flags)
{
if (!typeof(T).IsEnum)
throw new ArgumentException("The generic type parameter must be an Enum.");
if (flags.GetType() != typeof(T))
throw new ArgumentException("The generic type parameter does not match the target type.");
ulong flag = 1;
foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
{
ulong bits = Convert.ToUInt64(value);
while (flag < bits)
{
flag <<= 1;
}
if (flag == bits && flags.HasFlag(value as Enum))
{
yield return value;
}
}
}
Hi, how can we support a SelectList with your lib,
public IEnumerable<SelectListItem> Creating_a_select_list(State selected)
{
return State.GetAll().Select(
x => new SelectListItem
{
Selected = x == selected,
Text = x.Description,
Value = x.Value.ToString()
});
}
Hello!
I used this amazing library for many years on various projects. Now I have a new project that will be written with .net8.
I see Enums.Net was last time updated about a year ago. Is this project deprecated? Can I safely use it with latest .net (8 in this case)?
Thanks!
Don't use dictionary, because not safe.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.