Why can't I get the count of enums during compile time? - c#

I have asked How can I get the number of enums as a constant?, and I found out that I cannot get the count of enums during compile time, because C# uses reflection to do so.
I read What is reflection and why is it useful?, so I have a very basic understanding of reflection.
To get the count of enums, I can use Enum.GetNames(typeof(Item.Type)).Length;, and this happens during runtime using reflection.
I don't see any runtime knowledge needed to get the count of enums, because as far as I know, the count of enums cannot be changed during runtime.
Why does C# have to use reflection to get the count of enums? Why can't it do so during compile time?

Just because something can be evaluated at compile time doesn't mean that someone has programmed the compiler to do so. string.Format("{0:N2}", Math.PI) is another example.
The only way at present to get the count of the number of values of an Enum is by using reflection (Enum.GetNames or something similar). So it is not a constant expression, although technically the compiler could just evaluate the expression at compile-time and determine what the result is.
nameof is a perfect example. It is constant at compile-time, but there was no mechanism to extract the result at compile time until someone designed, developed, tested, documented, and shipped the feature. None of those are free, and thus the idea must compete for valuable resources (people, time, money) against other features that may be more valuable.
So if you feel that a compile-time construct like enumcount(Item.Type) is a valuable addition to the language, then you are more than welcome to post a suggestion on Connect and see if it makes it to the top of the feature list.
But, I need this number as a constant number, so that I can use it in Unity's [Range(int, int)] feature.
One non-ideal workaround is to define a constant that matches the current number of enum items, and throw an exception at run-time if the counts do not match:
Define a public constant right next to your enum, commenting it so that developers know to update it:
// Update this value any time the Type enum is updated
public const int TypeCount = 5;
public Enum Type
{
Bar1,
Bar2,
Bar3,
Bar4,
Bar5,
}
use it in your attribute:
[Range(0, Item.TypeCount)]
public void BlahBlahBlah() {}
and check it at the start of your app:
public static Main()
{
if(Enum.GetNames(typeof(Item.Type)).Length != Item.TypeCount)
throw new ApplicationException ("TypeCount and number of Types do not match.\nPlease update TypeCount constant.")
}

I think in simple terms:
Enums is one "type definition", .NET use Reflection when "type descriptor navigation" is needed.
So Enums is a Type and # runtime, if you want to count the defined enums voice you need to user a reflection.

I don't see any runtime knowledge needed to get the count of enums,
because as far as I know, the count of enums cannot be changed during
runtime.
Here is the mistake in your reasoning: Yes, the count of enums cannot be changed during runtime. However, it can be changed between runtime:
A.dll - version 1
public enum Foo { A }
A.dll - version 2
public enum Foo { Bar, Baz }
Replace version 1 of A.dll with version 2. The count of enums has changed (and the names of the values as well).
Why does C# have to use reflection to get the count of enums? Why
can't it do so during compile time?
It could do so. But then you would run into the problem above. The compile-time calculated value could become incorrect.

Related

How to write an extension method/class using two generics? [duplicate]

Given:
static TDest Gimme<TSource,TDest>(TSource source)
{
return default(TDest);
}
Why can't I do:
string dest = Gimme(5);
without getting the compiler error:
error CS0411: The type arguments for method 'Whatever.Gimme<TSource,TDest>(TSource)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
The 5 can be inferred as int, but there's a restriction where the compiler won't/can't resolve the return type as a string. I've read in several places that this is by design but no real explanation. I read somewhere that this might change in C# 4, but it hasn't.
Anyone know why return types cannot be inferred from generic methods? Is this one of those questions where the answer's so obvious it's staring you in the face? I hope not!
The general principle here is that type information flows only "one way", from the inside to the outside of an expression. The example you give is extremely simple. Suppose we wanted to have type information flow "both ways" when doing type inference on a method R G<A, R>(A a), and consider some of the crazy scenarios that creates:
N(G(5))
Suppose there are ten different overloads of N, each with a different argument type. Should we make ten different inferences for R? If we did, should we somehow pick the "best" one?
double x = b ? G(5) : 123;
What should the return type of G be inferred to be? Int, because the other half of the conditional expression is int? Or double, because ultimately this thing is going to be assigned to double? Now perhaps you begin to see how this goes; if you're going to say that you reason from outside to inside, how far out do you go? There could be many steps along the way. See what happens when we start to combine these:
N(b ? G(5) : 123)
Now what do we do? We have ten overloads of N to choose from. Do we say that R is int? It could be int or any type that int is implicitly convertible to. But of those types, which ones are implicitly convertible to an argument type of N? Do we write ourselves a little prolog program and ask the prolog engine to solve what are all the possible return types that R could be in order to satisfy each of the possible overloads on N, and then somehow pick the best one?
(I'm not kidding; there are languages that essentially do write a little prolog program and then use a logic engine to work out what the types of everything are. F# for example, does way more complex type inference than C# does. Haskell's type system is actually Turing Complete; you can encode arbitrarily complex problems in the type system and ask the compiler to solve them. As we'll see later, the same is true of overload resolution in C# - you cannot encode the Halting Problem in the C# type system like you can in Haskell but you can encode NP-HARD problems into overload resolution problems.) (See below)
This is still a very simple expression. Suppose you had something like
N(N(b ? G(5) * G("hello") : 123));
Now we have to solve this problem multiple times for G, and possibly for N as well, and we have to solve them in combination. We have five overload resolution problems to solve and all of them, to be fair, should be considering both their arguments and their context type. If there are ten possibilities for N then there are potentially a hundred possibilities to consider for N(N(...)) and a thousand for N(N(N(...))) and very quickly you would have us solving problems that easily had billions of possible combinations and made the compiler very slow.
This is why we have the rule that type information only flows one way. It prevents these sorts of chicken and egg problems, where you are trying to both determine the outer type from the inner type, and determine the inner type from the outer type and cause a combinatorial explosion of possibilities.
Notice that type information does flow both ways for lambdas! If you say N(x=>x.Length) then sure enough, we consider all the possible overloads of N that have function or expression types in their arguments and try out all the possible types for x. And sure enough, there are situations in which you can easily make the compiler try out billions of possible combinations to find the unique combination that works. The type inference rules that make it possible to do that for generic methods are exceedingly complex and make even Jon Skeet nervous. This feature makes overload resolution NP-HARD.
Getting type information to flow both ways for lambdas so that generic overload resolution works correctly and efficiently took me about a year. It is such a complex feature that we only wanted to take it on if we absolutely positively would have an amazing return on that investment. Making LINQ work was worth it. But there is no corresponding feature like LINQ that justifies the immense expense of making this work in general.
UPDATE: It turns out that you can encode arbitrarily difficult problems in the C# type system. C# has nominal generic subtyping with generic contravariance, and it has been shown that you can build a Turing Machine out of generic type definitions and force the compiler to execute the machine, possibly going into infinite loops. At the time I wrote this answer the undecidability of such type systems was an open question. See https://stackoverflow.com/a/23968075/88656 for details.
You have to do:
string dest = Gimme<int, string>(5);
You need to specify what your types are in the call to the generic method. How could it know that you wanted a string in the output?
System.String is a bad example because it's a sealed class, but say it wasn't. How could the compiler know that you didn't want one of its subclasses instead if you didn't specify the type in the call?
Take this example:
System.Windows.Forms.Control dest = Gimme(5);
How would the compiler know what control to actually make? You'd need to specify it like so:
System.Windows.Forms.Control dest = Gimme<int, System.Windows.Forms.Button>(5);
Calling Gimme(5) ignoring the return value is a legal statement how would the compiler know which type to return?
I use this technique when I need to do something like that:
static void Gimme<T>(out T myVariable)
{
myVariable = default(T);
}
and use it like this:
Gimme(out int myVariable);
Print(myVariable); //myVariable is already declared and usable.
Note that inline declaration of out variables is available since C# 7.0
This was a design decision I guess. I also find it useful while programming in Java.
Unlike Java, C# seems to evolve towards a functional programming language, and you can get type inference the other way round, so you can have:
var dest = Gimme<int, string>(5);
which will infer the type of dest. I guess mixing this and the java style inference could prove to be fairly difficult to implement.
If a function is supposed to return one of a small number of types, you could have it return a class with defined widening conversions to those types. I don't think it's possible to do that in a generic way, since the widening ctype operator doesn't accept a generic type parameter.
public class ReturnString : IReq<string>
{
}
public class ReturnInt : IReq<int>
{
}
public interface IReq<T>
{
}
public class Handler
{
public T MakeRequest<T>(IReq<T> requestObject)
{
return default(T);
}
}
var handler = new Handler();
string stringResponse = handler.MakeRequest(new ReturnString());
int intResponse = handler.MakeRequest(new ReturnInt());

dynamic and generics in C#

As discovered in C 3.5, the following would not be possible due to type erasure: -
int foo<T>(T bar)
{
return bar.Length; // will not compile unless I do something like where T : string
}
foo("baz");
I believe the reason this doesn't work is in C# and java, is due to a concept called type erasure, see http://en.wikipedia.org/wiki/Type_erasure.
Having read about the dynamic keyword, I wrote the following: -
int foo<T>(T bar)
{
dynamic test = bar;
return test.Length;
}
foo("baz"); // will compile and return 3
So, as far as I understand, dynamic will bypass compile time checking but if the type has been erased, surely it would still be unable to resolve the symbol unless it goes deeper and uses some kind of reflection?
Is using the dynamic keyword in this way bad practice and does this make generics a little more powerful?
dynamics and generics are 2 completely different notions. If you want compile-time safety and speed use strong typing (generics or just standard OOP techniques such as inheritance or composition). If you do not know the type at compile time you could use dynamics but they will be slower because they are using runtime invocation and less safe because if the type doesn't implement the method you are attempting to invoke you will get a runtime error.
The 2 notions are not interchangeable and depending on your specific requirements you could use one or the other.
Of course having the following generic constraint is completely useless because string is a sealed type and cannot be used as a generic constraint:
int foo<T>(T bar) where T : string
{
return bar.Length;
}
you'd rather have this:
int foo(string bar)
{
return bar.Length;
}
I believe the reason this doesn't work is in C# and java, is due to a concept called type erasure, see http://en.wikipedia.org/wiki/Type_erasure.
No, this isn't because of type erasure. Anyway there is no type erasure in C# (unlike Java): a distinct type is constructed by the runtime for each different set of type arguments, there is no loss of information.
The reason why it doesn't work is that the compiler knows nothing about T, so it can only assume that T inherits from object, so only the members of object are available. You can, however, provide more information to the compiler by adding a constraint on T. For instance, if you have an interface IBar with a Length property, you can add a constraint like this:
int foo<T>(T bar) where T : IBar
{
return bar.Length;
}
But if you want to be able to pass either an array or a string, it won't work, because the Length property isn't declared in any interface implemented by both String and Array...
No, C# does not have type erasure - only Java has.
But if you specify only T, without any constraint, you can not use obj.Lenght because T can virtually be anything.
foo(new Bar());
The above would resolve to an Bar-Class and thus the Lenght Property might not be avaiable.
You can only use Methods on T when you ensure that T this methods also really has. (This is done with the where Constraints.)
With the dynamics, you loose compile time checking and I suggest that you do not use them for hacking around generics.
In this case you would not benefit from dynamics in any way. You just delay the error, as an exception is thrown in case the dynamic object does not contain a Length property. In case of accessing the Length property in a generic method I can't see any reason for not constraining it to types who definately have this property.
"Dynamics are a powerful new tool that make interop with dynamic languages as well as COM easier, and can be used to replace much turgid reflective code. They can be used to tell the compiler to execute operations on an object, the checking of which is deferred to runtime.
The great danger lies in the use of dynamic objects in inappropriate contexts, such as in statically typed systems, or worse, in place of an interface/base class in a properly typed system."
Qouted From Article
Thought I'd weigh-in on this one, because no one clarified how generics work "under the hood". That notion of T being an object is mentioned above, and is quite clear. What is not talked about, is that when we compile C# or VB or any other supported language, - at the Intermediate Language (IL) level (what we compile to) which is more akin to an assembly language or equivalent of Java Byte codes, - at this level, there is no generics! So the new question is how do you support generics in IL? For each type that accesses the generic, a non-generic version of the code is generated which substitutes the generic(s) such as the ubiquitous T to the actual type it was called with. So if you only have one type of generic, such as List<>, then that's what the IL will contain. But if you use many implementation of a generic, then many specific implementations are created, and calls to the original code substituted with the calls to the specific non-generic version. To be clear, a MyList used as: new MyList(), will be substituted in IL with something like MyList_string().
That's my (limited) understanding of what's going on. The point being, the benefit of this approach is that the heavy lifting is done at compile-time, and at runtime there's no degradation to performance - which is again, why generic are probably so loved used anywhere, and everywhere by .NET developers.
On the down-side? If a method or type is used many times, then the output assembly (EXE or DLL) will get larger and larger, dependent of the number of different implementation of the same code. Given the average size of DLLs output - I doubt you'll ever consider generics to be a problem.

C# enums are similar to Java enums [duplicate]

What are some advantages of making enum in Java similar to a class, rather than just a collection of constants as in C/C++?
You get free compile time checking of valid values. Using
public static int OPTION_ONE = 0;
public static int OPTION_TWO = 1;
does not ensure
void selectOption(int option) {
...
}
will only accept 0 or 1 as a parameter value. Using an enum, that is guaranteed. Moreover, this leads to more self documenting code, because you can use code completion to see all enum values.
Type safety is one reason.
Another, that I find more important, is that you can attach metadata to enum values in Java. For example, you could use an enum to define the set of legal operations for a webservice, and then attach metadata for the type of request and data class:
AddItem(HttpMethod.POST, ProductEntry.class),
Java 5 enums originated from a typesafe enum pattern from Joshua Bloch's Effective Java (the first edition) to avoid the pitfalls of enums in C/C++/C# (which are simply thinly-veiled int constants) and the use in Java of final static int constants.
Primarily int constants and int enums aren't typesafe. You can pass in any int value. In C/C++ you can do this:
enum A { one, two, three };
enum B { beef, chicken, pork } b = beef;
void func(A a) { ... }
func((A)b);
Unfortunately the typesafe enum pattern from Effective Java had a lot of boilerplate, not all of it obvious. The most notable is you had to override the private method readResolve to stop Java creating new instances on deserialization, which would break simple reference checking (ie using the == operator instead of equals()).
So Java 5 enums offer these advantages over ints:
Type safety;
Java 5 enums can have behaviour and implement interfaces;
Java 5 enums have some extremely lightweight data structures like EnumSet and EnumMap.
Java 5 enums over these advantages over just using classes:
Less error-prone boilerplate (private constructor, readResolve() etc);
Semantic correctness. You see something is an enum and you know it's just representing a value. You see a class and you're not sure. Maybe there's a static factory method somewhere, etc. Java 5 enums much more clearly indicate intent.
Enums are already a class in Java.
If you're asking why this is better, I'd say that better type safety and the ability to add other attributes besides a mere ordinal value would come to mind.
In addition to better type safety, you can also define custom behavior in your enums (refer to Effective Java for some good examples).
You can use enums to effectively implement Singletons ^^:
public enum Elvis {
INSTANCE
}
Making enum a reference type that can contain fixed set of constants has led to efficient Map implementation like EnumMap and Set implementation like EnumSet (JDK classes).
From javadoc of EnumMap :
A specialized Map implementation for use with enum type keys. All of the keys in an enum map must come from a single enum type that is specified, explicitly or implicitly, when the map is created. Enum maps are represented internally as arrays. This representation is extremely compact and efficient.
EnumMap combines richness and type safety of Map with the speed of an array (Effective Java).
Enums are a type in itself - you cannot use an enum that does not exist, or put in some other similar looking constant. and also, you can enumerate them, so that code can be more concise.
using static constants could potentially cause maintenence nightmares - especially if they area spread out.
The only real advantage is that it can be used in a switch statement. All the other stuff an enum is capable of can just be done with plain vanilla class with a private constructor whose instances in turn are declared as public static final fields of the class in question (the typesafe pattern). The other advantage of enum is obviously that it makes the code less verbose than you would do with a plain vanilla class.
But if I'm not mistaken, in C++ (or was it C#?) you can use a String in a switch statement. So that advantage of enums in Java is negligible as opposed to C++. However, same thing was proposed for Java 7, not sure if it will make it.
Benefits of Using Enumerations:
An object can be created to work in the same manner as an enumeration. In fact,
enumerations were not even included in the Java language until version 5.0. However,
enumerations make code more readable and provide less room for programmer error.
OCA Java SE 7 Programmer I Study Guide

Benefits of using enums over directly using integral types?

1) I’m aware of the following benefits:
they increase the level of abstraction since you immediately see what underlying integral values represent.
You can use them instead of magic numbers and by doing that making the code more understandable
They also restrict the values an enum variable can have and in doing so make the application safer, since programmers know which values are valid for variable, so I guess they sort of provide a type safety
Are there any other benefits they provide over directly using integral values?
2) Why do they use integrals as an underlying type and not string?
thank you
You've listed a lot of the core reasons where enums are preferable to integral types.
Named constants are safer and more readable than magic numbers
Enums describe to programmers what they are for. Integral values don't.
Naturally limiting the set of values that can be passed in. (You've got the tip of the type-safety iceberg... but look deeper...)
You can also add:
Vastly increased Type Safety. If you accept an 'int', then any int can be passed in. If you accept a VehicleType, then only a VehicleType can be passed in. I'm not just talking about someone passing in 6 when the largest allowed number is 5. I mean what if you pass in FuelType.Unleaded to a function that thinks it means VehicleType.Aeroplane? With enums the compiler will tell you you're an idiot. An integral type says "yeah, 5 is fine with me" and your program exhibits really odd behaviour that may be extremely difficult to trace.
Easier refactoring. Just as with any magic constants, If you pass in the value 5 in a hundred places in your program, you're in trouble if you decide to change 5 to have a different meaning. With an enum (as long as you don't have binary backwards compatibility concerns) you can change the underlying values. You can also change the underlying type of an enum if you wish (byte -> int -> long) without having to do anything more than recompile the client code.
Bitfields are so much easier to work with when the bits and masks can be named. And if you add new bits, you can often arrange things so that merely updating the related masks will allow most of your existing code to handle the new bitfields perfectly without having to rewrite them from scratch.
Consistency throughout the program. If you are careful with obfuscation and type safety, enums allow you to represent a list of named values that a user chooses from with the same names in the code, but without the efficiency cost of using strings.
Everybody understands why constants are great in code. Enums simply give you a way of holding together a related group of constants. You could achieve the same thing in a messier manner using a namespace of consts.
Using an enum for a parameter rather than a bool not only makes the code self-documenting, readable, and less prone to mistakes. It also makes it much easier to add a third option when you realize that two options isn't enough.
As with all tools, enums can be misused. Just use them where they make sense.
2) Why use bytes or ints instead of strings? Simply they're small and efficient.
I would conjecture that they require underlying integral types to ensure simplicity of comparison and more easily support bit flags. Without that limitation, we, or the compiler, or the runtime, would likely have to resort to some fuzziness to do things like combinations - or we would get into a situation where - as you say - we shouldn't care about the underlying type (the point of the abstraction) and yet when we try to say A | B we get a runtime error because we used an underlying type that isn't capable of that type of operation.
One benefit is when you want to use enum as a flag.
So if you define an enum like this:
[Flags]
public enum TestEnum{ A, B, C, D };
Then if you have a method that accept an instance of TestEnum as a variable, you can combine the values from the enum, so you can send for example A | B | C as the parameter for the method. Then, inside the method, you can check the parameter like this:
if ((paramname & TestEnum.A) > 0)
{
//do things related to A
}
if ((paramname & TestEnum.B) > 0)
{
//do things related to B
}
//same for C and D
Also, I think the reasons you mention are good enough by themselves to use enums.
Also regarding the comment that you can force an wrong value into an enum with code like this (TestEnum)500; it's hard to do if you do not want to break your code.
The point that the value 0 for an enum should be the default value, or in the case of flags "the absence of all other flags" is very important, since the line TestEnum myenum will instanciate myenum as 0 regardless if you have defined any enum value for 0 or not.
You can also parse an Enum from the string representation. You may get that string from a data source or user-entry.
I think you sold me on Enums at "magic numbers".
The main benefit of enum is that constants can be referred to in a consistent, expressive and type safe way.
Readability is of-course the topmost advantage of using the enumeration.
Another advantage is that enumerated constants are generated automatically by the compiler.
For instance, if you had an enumerated constant type for error codes that could occur in your program, your enum definition could look something like this:
enum Error_Code
{
OUT_OF_MEMORY,
FILE_NOT_FOUND
};
OUT_OF_MEMORY is automatically assigned the value of 0 (zero) by the compiler
because it appears first in the definition.FILE_NOT_FOUND equal to 1, so on.
If you were to approach the same example by using symbolic constants or Magic numbers, you write much more code to do the same.

Why Should You Use The C# Predefined Types Rather Than The Aliases In The System Namespace

In the "C# Coding Standard" by Juval Lowy available from www.idesign.net, the recomendation is made to use the C# predefined types instead of the aliases in the System namespace, e.g.:
object NOT Object
string NOT String
int NOT Int32
What is the benefit of this? How do they differ? I have followed this advise in my own coding but never knew how they differed.
The main time they are unexpectedly different is when someone is stupid enough to call a type (or property /field/etc) String (for example), since string always refers to global::System.String, where-as String could be YourNamespace.String.
The closest you can get to the C# alias is #string, which tends to stick out like a sore thumb.
I prefer the C# aliases.
btw, here's a fun way to mess with anyone using dynamic too much:
using dynamic = System.Object;
They don't really differ. Personally I use the aliases too, but Jeff Richter advocates the exact opposite. The generated code will be exactly the same. Use whichever you find most readable (and try to be consistent).
One thing most people agree on: when writing an API, use the type name rather than the alias, so:
int ReadInt32()
rather than
int ReadInt()
the int part doesn't matter here - it's not part of the name, and can be displayed appropriately to any consumer using any language... but the method name should be language-neutral, which means using the type name.
One place where you have to use the alias is when specifying the underlying type for an enum:
enum Foo : byte // Valid
enum Foo : System.Byte // Invalid
In addition to what Jon said here is another difference.
var x = (Int32)-y; // Does not compile.
var x = (int)-y; // Negates the value of y and casts as an int.
This is because of a grammar disambiguation rule defined in §7.6.6 of the C# Programming Language specification.
I think using the 'blue' int, string, etc.. might be a little more intuitive to read. Otherwise, I use the class when calling a static method on it i.e. Int32.TryParse()
I always use the aliases when specifying the type in a parameter, property or method signature or field (so: almost everywhere) except when calling a static member on such a type.
String.Format("{0}", 1);
Int32.Parse("123");
String.IsNullOrEmpty(value);
Here's another compiler-based difference:
public enum MyEnum : Byte {Value1, Value2} //does not compile
public enum MyEnum : byte {Value1, Value2} //ok
The only difference is that they're nicer to read (this of course is a matter of opinion). The compiled result is exactly the same bytecode.
The Entity Framework code generator uses predefined types, so if you want to be able to implement the Visual Studio 2017 coding style rules fully you will need to choose predefined types (int instead of Int32, etc). Otherwise your generated code will not be in compliance.
(Options->Text Editor->C#->Code Style->General->predefined type preference)

Categories

Resources