How can I get the number of transfers as a constant?

From the total number of elements defined in the enumeration , I see that I can get the number of enumerations using:

Enum.GetNames(typeof(Item.Type)).Length; 

It works great!

But I need this number as a constant number, so I can use it in Unity [Range(int, int)] .

 private const int constEnumCount = Enum.GetNames(typeof(Item.Type)).Length; 

The above does not work because enumeration counting is not a constant number, so I cannot assign it to a constant variable.

How can I get the number of transfers as a constant?

+6
source share
5 answers

It is not possible to get the number of enumerations as const . Enum.GetNames uses reflection to get these things, and this is essentially a run-time operation. Therefore, it cannot be known at compile time, which is a requirement for const .

+9
source

Unfortunately, this cannot be done in any meaningful way due to technical limitations:

  • [Range(int,int)] is an attribute, and all information provided to the attribute must be const
  • The only really bulletproof way to get the number of values ​​in an enumeration is to use Enum.GetValues(typeof(MyEnum)).Length or Enum.GetNames(typeof(MyEnum)).Length , both of which are a reflection of the runtime.

However, there are hacks that may work. For example, an enumeration value may be cast for an integer. While no one explicitly defines values ​​for your enums, you can use the last element in your enum like this:

 [Range(0,(int)MyEnum.LastValue)] public void BlahBlahBlah() {} 

However, be aware that as soon as someone adds a new entry to the enumeration after you use or reorder the elements in the enumeration, your code will be unpredictable and not behave the way you want.

This is sad, but the C # compiler is not smart enough to do simple math in a compiler such as Java, C, and C ++ compilers. Therefore, even the example I gave will really work only if LastValue never used for anything other than marking the last element in the enumeration. This reduces the complexity of the C # compiler, which also greatly improves the compilation speed for your application. So there are some tradeoffs that the C # team and CLR have taken to improve your experience elsewhere.

+2
source

Assuming you need const because you are trying to specify values ​​for an attribute ( this ?), Then you are out of luck.

Your options:

  • Hardcode is the count in the attribute declaration or as const and be careful to synchronize the count with the enum definition
  • Use PostSharp or some other aspect-oriented structure to insert this attribute. I never did it myself, but it looks ( How to add an attribute using the PostSharp attribute? )

Perhaps you can also somehow redo this with T4 templates, but it will be overly inconvenient.

This is me, if you do not say, but hundreds of different sets of enumerations, I would encode the length and, possibly, add Assert, where I need it.

 // WARNING - if you add members update impacted Range attributes public enum MyEnum { foo, bar, baz } [Range(0, 3)] class Test { public Test() { int enumCount = Enum.GetNames(typeof(MyEnum)).Length; int rangeMax = GetType().GetCustomAttributes(typeof(Range), false).OfType<Range>().First().Max; Debug.Assert(enumCount == rangeMax); } static void Main(string[] args) { var test = new Test(); } } 
+2
source

You cannot assign / create const at runtime. This is what you are trying to do. A const should be fully evaluated at compile time , and not at run time.

I'm not sure about Unity (and why it requires const ), but I would be looking for using readonly

 private readonly int constEnumCount = Enum.GetNames(typeof(Item.Type)).Length; 
+1
source

In C #, a const is defined as a constant, that is, the value (and not the calculation that created it!) Is directly embedded in the compiled assembly.

So that you do not do something problematic, the compiler does not allow you to assign the result of the calculation to a constant. To understand why, imagine that this is possible:

 A.dll public enum Foo { A, B } B.dll public const NumberOfFoos = Enum.GetNames(typeof(Foo)).Length; // Compiles to: B.dll public const NumberOfFoos = 2; 

Now you change A.dll:

 A.dll public enum Foo { A, B, C, D } B.dll public const NumberOfFoos = 2; // Oh no! 

Therefore, you will need to recompile B.dll to get the correct value.

Deteriorating: Imagine you had a C.dll assembly that uses B.NumberOfFoos. The value 2 will be directly embedded in C.dll, so it will also need to be recompiled after B.dll to get the correct value. Therefore (pit of success), C # does not allow you to fulfill this assignment in const.

0
source

All Articles