Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 构造函数限制_C#_Class_Restriction - Fatal编程技术网

C# 构造函数限制

C# 构造函数限制,c#,class,restriction,C#,Class,Restriction,我想知道是否有一种方法可以限制构造中的值。这是我的密码: class Student : Human { private double Grade; public Student(string FirstName, string LastName, double Grade) : base(FirstName, LastName) { this.FirstName = FirstName; this.LastName =

我想知道是否有一种方法可以限制构造中的值。这是我的密码:

class Student : Human 
{
    private double Grade;

    public Student(string FirstName, string LastName, double Grade)
        : base(FirstName, LastName)
    {
        this.FirstName = FirstName;
        this.LastName = LastName;
        this.Grade = Grade;
    }
}

当我成为一名新学生时,我想将分数限制在>=2.00和之间,你可以检查它,并在运行时抛出一个异常,如下所示:

if (grade < 2.00 || grade > 6.00)
    throw new ArgumentOutOfRangeException("grade");
double userInput = GetUserInputForGrade();
Grade grade = (Grade)userInput; // perform explicit cast.
Student student = new Student(firstName, lastName, grade);
但是,有一种方法可以使用代码契约获取此类事件的编译时警告。您可以下载,也可以在那里找到文档。它只与Visual Studio的非Express版本集成,由Microsoft编写。它将检查方法调用是否可能遵守您指定的约定。您的代码将变成:

using System.Diagnotistics.Contracts;

public Student(string firstName, string lastName, double grade)
    : base(firstName, lastName)
{
    #region Contract
    Contract.Requires<ArgumentOutOfRangeException>(grade >= 2.00);
    Contract.Requires<ArgumentOutOfRangeException>(grade <= 6.00);
    #endregion
    this.FirstName = firstName;
    this.LastName = lastName;
    this.Grade = grade;
}
使用System.Diagnostics.Contracts;
公立学生(字串姓氏、字串姓氏、双年级)
:base(firstName,lastName)
{
#区域合同
合同要求(等级>=2.00);
合同要求(等级<代码>班级学生:人
{
私人双年级;
公立学生(字串姓氏、字串姓氏、双年级)
:base(FirstName,LastName)
{
this.FirstName=FirstName;
this.LastName=LastName;
这个。等级=等级;
如果(等级>=2,等级
班级学生:人类
{
私人双年级;
公立学生(字串姓氏、字串姓氏、双年级)
:base(FirstName,LastName)
{
如果(等级<2 | |等级>6)
抛出新ArgumentOutOfRangeException(“分数必须介于2和6之间”);
this.FirstName=FirstName;
this.LastName=LastName;
这个。等级=等级;
}
}
公立学生(string FirstName、string LastName、双年级)
:base(FirstName,LastName)
{

如果(Grade>=2.0 | | Grade,则可以引发异常:

class Student : Human 
{
    private double Grade;

    public Student(string FirstName, string LastName, double Grade)
        : base(FirstName, LastName)
    {
        if (Grade >= 2 && Grade <= 6) { 
          throw new ArgumentOutOfRangeException();
        }

        this.FirstName = FirstName;
        this.LastName = LastName;
        this.Grade = Grade;
    }
}
班级学生:人类
{
私人双年级;
公立学生(字串姓氏、字串姓氏、双年级)
:base(FirstName,LastName)
{

如果(Grade>=2&&Grade如果你想有编译时检查的机会,你必须使用代码契约。它们本质上是运行时的异常,因此相当于带异常的参数验证

public Student(string firstName, string lastName, decimal grade)
{
    Contract.Requires(grade >= 2);
    Contract.Requires(grade <= 6);

    FirstName = firstName;
    LastName = lastName;
    Grade = grade;     
}
public Student(string firstName、string lastName、十进制分数)
{
合同要求(等级>=2);

Contract.Requires(grade还有一个选项,可能有点复杂,但可以确保给定的范围,根本不使用
double
,而是创建一个名为
grade
的自定义类。您的
grade
类将包含从和到
double
的强制转换,并将强制执行验证。 这意味着所有年级验证逻辑都在
Grade
结构中,
Student
类只接收一个
Grade
对象,不必担心它

public struct Grade
{
    public static readonly double MinValue = 2.0;
    public static readonly double MaxValue = 6.0;

    private double value;

    public static explicit operator double(Grade grade)
    {
        return grade.value + MinValue;
    }

    public static explicit operator Grade(double gradeValue)
    {
        if (gradeValue < MinValue || gradeValue > MaxValue)
            throw new ArgumentOutOfRangeException("gradeValue", "Grade must be between 2.0 and 6.0");

        return new Grade{ value = gradeValue - MinValue };
    }
}
Edit:我已经用@EricLippert的建议更新了代码,以使类向开发人员公开其最小/最大值


编辑2:根据@JeppeStigNielsen的建议再次更新。
value
字段现在存储与MinValue的偏移量,因此调用
default(Grade)
将返回有效值(等于MinValue)无论0是否在有效范围内。

不要认为您可以将其设置为编译时错误,但是,假设
Grade
是用户输入,您可以运行检查以确保它在您的范围内,然后让用户知道是否失败。您真的想要双精度?还是想要十进制?请记住,双精度不能仅代表分母上不是二次幂的分数。ArgumentOutOfRangeException为+1,但与区域不一致。为什么不合并为一个Requires子句?
Contract.Requires(grade>=2.00&&grade@Andy代码契约过去不擅长处理复合要求/保证和不变量。我不确定情况是否仍然如此,但为了这一点和可读性(长行等)我将它们分开。异常由程序员决定,因为我们没有足够的信息说明为什么分数不应该在1到7之间,不应该意味着应该抛出一个特定的异常,例如ArgumentOutOfException。@SpaceApple有一条一般规则,你决不能只抛出异常。这违反了.Net最佳实践。True.ArgumentException在这种情况下也是无效的,因为它可能无法满足程序员的需要。但我确实理解您的观点。但是,您会丢失所有运算符、所有比较和相等方法,并且任何接受
double
的方法将不再接受您的
Grade
@Virtlink:因此,如果你错过了它们。我喜欢这个想法,但我会将常量设置为公共静态只读字段。公共是因为我们希望用户能够知道double何时超出范围。静态是因为它的类型范围。只读不是常量,因为范围将来可能会改变。@EricLippert此结构存在
default(Grade)的问题
(或等效地
new Grade()
)将创建
Grade
结构的“非法”值
0.0
。在这种情况下不会运行您的检查。解决方法之一是存储与
2.0
相比的多余值(
MinValue
)在实例字段中。例如,如果实际分数为
2.5
,则存储
0.5
。然后,您的转换运算符必须进行相加(分别减去)
MinValue
在它们返回之前
return
@JeppeStigNielsen:非常好的一点!记住结构的默认值始终是合法值,这一点很重要。第一个示例中的条件是反向的。它在2到6之间的等级上抛出,而不是在那些等级上抛出,除非是在这些等级上抛出。@LawrenceJohnston谢谢,我已经看到了修正了它。
class Student : Human 
{
    private double Grade;

    public Student(string FirstName, string LastName, double Grade)
        : base(FirstName, LastName)
    {
        if (Grade >= 2 && Grade <= 6) { 
          throw new ArgumentOutOfRangeException();
        }

        this.FirstName = FirstName;
        this.LastName = LastName;
        this.Grade = Grade;
    }
}
class Student : Human  {
    private double Grade;

    public Student(string FirstName, string LastName, double Grade)
        : base(FirstName, LastName)
    {
        System.Diagnotistics.Contracts.Contract.Requires<ArgumentOutOfRangeException>(Grade >= 2 && Grade <= 6);

        this.FirstName = FirstName;
        this.LastName = LastName;
        this.Grade = Grade;
    }
}
public Student(string firstName, string lastName, decimal grade)
{
    Contract.Requires(grade >= 2);
    Contract.Requires(grade <= 6);

    FirstName = firstName;
    LastName = lastName;
    Grade = grade;     
}
public struct Grade
{
    public static readonly double MinValue = 2.0;
    public static readonly double MaxValue = 6.0;

    private double value;

    public static explicit operator double(Grade grade)
    {
        return grade.value + MinValue;
    }

    public static explicit operator Grade(double gradeValue)
    {
        if (gradeValue < MinValue || gradeValue > MaxValue)
            throw new ArgumentOutOfRangeException("gradeValue", "Grade must be between 2.0 and 6.0");

        return new Grade{ value = gradeValue - MinValue };
    }
}
double userInput = GetUserInputForGrade();
Grade grade = (Grade)userInput; // perform explicit cast.
Student student = new Student(firstName, lastName, grade);