简体   繁体   English

限制构造函数AT DESIGN TIME中参数的值

[英]Restrict value of a parameter in a constructor AT DESIGN TIME

I'd like to restrict the value of a number parameter in a constructor to within a certain range. 我想将构造函数中的number参数的值限制在一定范围内。

I know the conventional way is to do something like the following: 我知道传统的方法是做类似以下的事情:

public class Foo
{
    public int MaxAmount { get; }
    public int Amount { get; set; }

    public Foo(int amount)
    {
        if (amount > MaxAmount) { Amount = MaxAmount; }
        else if (amount < 1) { Amount = 1; }
        else { Amount = amount; }
    }
}

But what I don't like about this is that the caller doesn't know when the property gets set to something other than what was specified. 但我不喜欢的是调用者不知道属性何时设置为指定的内容。 I could return an exception instead of silently clamping the value, but that's not very friendly. 我可以返回一个异常,而不是默默地夹住值,但这不是很友好。

What I'd like is something akin to this: 我想要的是类似于此的东西:

public Foo(int(1, this.MaxAmount) amount) // Where int(minimumValue, maximumValue)
{
   Amount = amount;
}

in which one wouldn't even be able to instantiate Foo with an unacceptable value - the framework would prevent it. 其中一个人甚至无法用不可接受的值来实例化Foo - 框架会阻止它。

Is anything like this possible? 有可能这样吗?

EDIT FOR CLARITY: 编辑清晰度:

What I'm after is a means by which the parameter itself can carry and communicate the information about its constraints - in a 'baked in' fashion which might, for example, surface in Intellisense when you wrote the call. 我所追求的是一种方法,参数本身可以携带并传递有关其约束的信息 - 以“烘焙”方式,例如,当您编写呼叫时,可能会在Intellisense中浮现。 So, I'd avoid the work of even attempting to instantiate the class if the values for the parameters were not valid. 因此,如果参数的值无效,我甚至会避免尝试实例化类的工作。

If, for example, the program is running and the user types a number (N) and presses a button which creates a new Foo with an illegal quantity of N, I now have an exception to handle and something to debug and fix. 例如,如果程序正在运行并且用户键入数字(N)并按下创建具有非法数量N的新Foo的按钮,那么我现在有一个例外来处理并调试和修复。 Why even allow it in the first place? 为什么甚至首先允许它? If Foo has been explicitly defined as having an upper boundary of 4 for its Amount property, what's the point of allowing the developer to write Foo(5) when I could have informed him that the value he's passing is not valid at the time that he wrote it? 如果Foo已被明确定义为其Amount属性的上限为4,那么当我可以告诉他他正在传递的值在他没有效时,允许开发人员编写Foo(5)是什么意思?写了吗?

If there's some syntactic sugar, like ParameterConstraint or something, that is handled by the Framework for me so that I don't have to roll my own into every class I write, I think that would be very useful. 如果有一些语法糖,比如ParameterConstraint或者其他东西,那么框架对我来说是这样的,这样我就不必自己卷入我写的每一个类中,我认为这非常有用。

I could return an exception instead of silently clamping the value, but that's not very friendly. 我可以返回一个异常,而不是默默地夹住值,但这不是很友好。

Say what? 说什么? What do you mean, "friendly"? 你是什​​么意思,“友好”? The caller isn't your friend, it's another piece of code that is trying to set an out of range value. 调用者不是你的朋友,它是另一段试图设置超出范围值的代码。 The developer who wrote the code should be told immediately that he's doing something wrong. 应该立即告诉编写代码的开发人员他做错了什么。

Throw an exception! 抛出异常!

You can do this using static-contract checking with Code Contracts (Premium only - The standard edition only offers runtime contract checking). 您可以使用代码合同进行静态合同检查(仅限Premium - 标准版仅提供运行时合同检查)。

The syntax is simply 语法很简单

public Foo(int amount) {
    Contract.Requires(amount < MaxAmount);
    ...
 }

(Requires) contracts are evaluated by checking that the arguments is constrained when calling the method. (Requires)通过在调用方法时检查参数是否受约束来计算合同。 In your instance, it will be difficult to evaluate the constructor argument with against the instance field MaxAmount, because you cannot check that value beforehand. 在您的实例中,很难使用实例字段MaxAmount来评估构造函数参数,因为您无法事先检查该值。 (Make MaxValue static to solve this). (使MaxValue静态以解决此问题)。

Example of such call. 这种电话的例子。

int val = _getFromSomewhere();
var foo = new Foo(val); 
//This May produce compile time error 
// because the contract checker cannot prove you contract is met.

The fix would be to make sure you put the constraint where you call is made. 修复方法是确保将约束放在调用的位置。

int val = _getFromSomewhere();
if (val < Foo.MaxAmount)
    var foo = new Foo(val); 
    //Will always compile fine, because contract is met.

When you install Contracts, the static checker isn't turned on by default. 安装“合同”时,默认情况下不会打开静态检查器。 Your project properties will have an extra tab where you can configure the contract options and enable static checking. 您的项目属性将有一个额外的选项卡,您可以在其中配置合同选项并启用静态检查。

You will need to wrap the parameter up in a new type then. 然后,您需要将参数包装为新类型。 ints know what their max amount is, and it is int.MaxValue. int知道它们的最大数量是多少,它是int.MaxValue。 If it is truly the case that the parameter itself knows its own max amount, and that it isn't something specific to class Foo, then you will need to create another type that checks the amount passed in to it. 如果确实参数本身知道它自己的最大数量,并且它不是Foo类特有的,那么你需要创建另一个类型来检查传入它的数量。 As it stands, the signature of Foo's constructor accepts any int data structure. 就目前而言,Foo构造函数的签名接受任何int数据结构。

Either throw the exception or provide a static property to validate the amount 抛出异常或提供静态属性来验证金额

public static bool ValidateAmount(int amount)
{
    if(amount > MaxAmount)
        return false;
    return true;
}

Not for sure if this works for properties types in C#, but you might be able to define an enumeration contain all of the acceptable values and then set the data type of the property to that enumeration. 不确定这是否适用于C#中的属性类型,但您可以定义包含所有可接受值的枚举,然后将属性的数据类型设置为该枚举。 That would force the caller to use the enumeration and thus know what values are acceptable. 这会强制调用者使用枚举,从而知道哪些值是可接受的。 Of course, if you have a lot of values in the acceptable range, the enumeration would be unwieldy. 当然,如果你有很多值在可接受的范围内,枚举将是笨重的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM