限制方法参数中的枚举值

发布于 2024-08-29 13:31:45 字数 473 浏览 3 评论 0原文

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


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

抱歉举了这个蹩脚的例子,但希望你能明白。有没有办法限制 PeelFruit 接受的枚举值?

显然,我可以用开关或其他东西在方法中检查它们,但如果有一种方法可以做到这一点,那就太酷了:a)更紧凑一点,b)会导致编译时错误,而不是运行时错误错误。

[Fruit = Orange,Bannana]
void PeelFruit(Fruit fruit) { ... }
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 constrain the enum values that PeelFruit will accept?

Obvisouly I could check them in the method with a switch or something, but it would be cool if there was a way to do it that is a) a bit more compact, and b) would cause a compile time error, not a run time error.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

戴着白色围巾的女孩 2024-09-05 13:31:45

这对于基本语言功能来说是不可能的(使用代码契约是可能的) ,尽管编译时检查仅适用于高级版)。事实上,您甚至无法将输入限制为 enum 中定义的值!接受 Fruit 参数的方法将接受任何 int(或者任何枚举类型,如果它不是整数),只要调用者将其转换为首先是水果

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

This isn't possible with base language features (it's possible with code contracts, though compile-time checking is only available with the premium edition). In fact you can't even constrain your input to the values defined in your enum! A method that accepts a Fruit parameter will accept any int (or whatever the enumeration's type is, if it isn't an integer), as long as the caller casts it to Fruit first:

PeelFruit((Fruit)10000); // Not a Fruit? Not a problem!
乙白 2024-09-05 13:31:45

从你的例子中并不清楚你真正想要做什么。您不能像您建议的那样对枚举进行限制,因为枚举的所有值都是等效的且类型相同。编译器只关心类型,而不关心值,因此无法区分。

如果出于某种特殊原因不需要枚举,则实现相同目标的一种方法是使用类型系统来发挥您的优势。定义对象层次结构而不是枚举。如果您愿意,对象本身可以是单例占位符。这样你就可以使用类型系统来做到这一点。举个例子

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 ....) { }

有意义吗?

It isn't clear from your example what you're really trying to do. You can't have constraints on enums like you suggest because all values of an enum are equivalent and the same type. The compiler only cares about types, not values, so it can't differentiate.

One way you can achieve the same thing, if the enum is not required for some special reason, would be to use the type system to your advantage. Instead of the enum, define an object heirarchy. The objects themselves can be singleton place holders if you like. This way you can use the type system to do this. 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?

给不了的爱 2024-09-05 13:31:45

您可以使用 代码合约。我相信你可以做这样的事情:

Contract.Requires(fruit != Fruit.Strawberry) 

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

Contract.Requires(fruit != Fruit.Strawberry) 
她如夕阳 2024-09-05 13:31:45

一种可能性是使用对象来表示水果而不是使用枚举。这将使您能够进行编译时检查。

每个水果类都会实现接口来说明它们允许或不允许的内容。

取而代之的

void PeelFruit(Fruit fruit) { ... }

void PeelFruit(IPeelable fruit) { ... }

A possibility would be to use objects to represent the fruit instead of using enums. This would enable you to have compile time checks.

Each fruit class would implement interfaces to say what they allow or dont allow.

Instead of

void PeelFruit(Fruit fruit) { ... }

it would be

void PeelFruit(IPeelable fruit) { ... }
摘星┃星的人 2024-09-05 13:31:45

一种非常简单的方法是分配数值,因此在您的示例中

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

然后检查

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

Well one very easy way would be 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
...
甜心小果奶 2024-09-05 13:31:45

您建议的是一个属性,它是运行时实体,而不是编译时实体。确实没有办法按照你的建议去做,但你真的必须问自己设计是否正确。如果您控制枚举,也许拥有两个单独的枚举会更有意义。就像 PeelableFruitNonPeelableFruit 一样。

What you're proposing is an Attribute which is a run-time entity, not compile time. There's really no way to do what you're proposing, but you really have to ask yourself if the design is correct. If you're in control of the enum, maybe having two separate enums would make more sense. Like PeelableFruit and NonPeelableFruit.

网白 2024-09-05 13:31:45

有 2 个枚举,一个用于可剥皮水果,一个用于不可剥皮水果?如果枚举不适用于所有情况,那么它们无论如何都应该是单独的东西。

使用带有 Fruit、peelableFruit 等实例的类型层次结构可能会更好地解决这个问题,这将迫使编译器进行类型检查,正如已经指出的那样,无论如何,这不会真正在 Enum 上完成。

您可以使用没有任何功能的 Marker 接口来识别类型并允许将它们传递给方法。

Have 2 enums, one for peelable fruit, and one for non-peelable fruit? If the enum does not apply to all cases then they should probably be separate things anyway.

this is probably better solved using a type hierarchy with instances of fruit, peelableFruit etc, which would force the compiler to do type checking, which won't really be done on the Enum anyway, as has been pointed out.

You could use Marker interfaces, with no functionality, to identify the types and allow them to be passed to methods.

九厘米的零° 2024-09-05 13:31:45

如果您想要编译时检查,那么恐怕您将不得不采用类层次结构。

如果您满足于运行时检查,那么最紧凑的形式将是检查值的函数。

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

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

如果您希望调用者能够验证他们没有传递错误的值,请将其设为公共函数。那么他们就不必处​​理异常了。

If you want compile-time checks, then I'm afraid you'll have to go with a class heirarchy.

If you'll settle for run-time checks, then the most compact form would be a function that checks the 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 verify that they are not passing an incorrect value. Then they won't have to handle the exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文