Constraining enum value in method parameter

enum Fruit
{
    Banana,
    Orange,
    Strawberry
    ...
    ...
    // etc, very long enum
}


PeelFruit(Fruit.Orange);
PeelFruit(Fruit.Banana);
PeelFruit(Fruit.Strawberry); // huh? can't peel strawberries!

      

Sorry for the lame example, but hopefully you get the idea. Is there a way to limit the values ​​the enumeration will accept PeelFruit

?

Obvisouly I could check them in a method with a switch or something, but it would be great if there was a way to do this: a) a little more compact, and b) throw a compile time error, not a runtime error ...

[Fruit = Orange,Bannana]
void PeelFruit(Fruit fruit) { ... }

      

+2


a source to share


8 answers


This is not possible with basic language features (possibly with code contracts , although compile-time checking is only available in the list price ). In fact, you cannot even limit your input to the values ​​specified in enum

! A method that takes a parameter Fruit

will accept any int

(or any enumeration type if it is not an integer) as long as the caller passes it in first Fruit

:



PeelFruit((Fruit)10000); // Not a Fruit? Not a problem!

      

+5


a source


It is not clear from your example what you are really trying to do. You cannot have restrictions on enums as you suggest, because all enumeration values ​​are equivalent and the same. The compiler only cares about types, not values, so it cannot differentiate.

One way to achieve the same, if the enumeration is not required for some specific reason, would be to use the type system to your advantage. Instead of listing, specify the object hierarchy. The objects themselves can be single point holders if you like. So you can use the type system for that. As an example



public abstract class Fruit { protected PeelableFruit() { } };
public abstract class PeelableFruit : Fruit { protected PeelableFruit() { } };
public class Orange : PeelableFruit { public static readonly Instance = new Orange(); protected Orange() { } };
etc. etc.

void AcceptsAnyFruit(Fruit ....) { }
void AcceptsPeelableFruit(PeelableFruit ....) { }

      

Make sense?

+3


a source


You can get compiler checking using code contracts . I believe you can do something like this:

Contract.Requires(fruit != Fruit.Strawberry) 

      

+1


a source


Perhaps it would be better to use objects to represent fruits instead of using enums. This will allow you to perform compile-time checks.

Each fruit class will implement interfaces to say what they allow or not allow.

Instead

void PeelFruit(Fruit fruit) { ... }

      

This will

void PeelFruit(IPeelable fruit) { ... }

      

+1


a source


Well, a very simple way is to assign numeric values, so in your example

enum Fruit
{
    Banana = 1,
    Orange = 2,
    Strawberry = 4
    ...
    ...
    // etc, very long enum
}

      

Then check

if ((int) thefruit > 2)
...
else
...

      

0


a source


Are there 2 checklists, one for flaky fruits and one for uncompressed fruits? If the enumeration does not apply to all cases, then they probably should be different.

this is probably better handled by using a type hierarchy with examples of fruits, peelableFruit, etc., which forces the compiler to do type checking, which will not actually be done in an Enum as stated.

You can use Marker interfaces without any functionality to identify types and let them pass methods.

0


a source


What you are suggesting is an attribute, which is a runtime object, not compile time. There is really no way to do what you suggest, but you really need to ask yourself if the design is correct. If you are in control of an enumeration, it might make more sense to have two separate enumerations. As PeelableFruit

and NonPeelableFruit

.

0


a source


If you need compile time checks, I'm afraid you'll have to go with a class hierarchy.

If you agree to run-time validation, the most compact form would be a function that validates a value.

void PeelFruit(Fruit fruit)
{
    if (!Peelable(fruit))
        throw new ArgumentException("Fruit is nonpeelable."); 
    ... 
} 

static bool Peelable(Fruit fruit) { ... }

      

Make it a public function if you want your callers to be able to make sure they are not passing in the wrong value. Then they won't have to handle the exception.

0


a source







All Articles