首页 文章

对于类和对象上的Dietel C#练习,这是一个令人满意的答案吗?

提问于
浏览
0

基本上,我'm trying to teach myself C#. And tbh, I really don'获得了C#做类的方式 . 这本书教你的方式,他们说使用字段,构造函数和属性 . 为什么你的代码中有3种方法可以写同样的东西?!我将该字段视为"field_length",方法变量为"Length",构造函数为"length"(小写) .
这简化了什么?你有这些获取/设置访问器,这真的增加了混乱 . 书中说:这样做 . 但有人可能会提供一些理由让所有这些't do anything purposeful, but basically is there to support one or two lines of useful code. (In this case it'只是一个练习课来进行两个简单的矩形计算 . 两行有用的代码只是area = length * width和perimeter = 2 * length 2 * width,其余部分占用了整个页面!

所以,这是Dietel第10章关于课程第402页的问题 . 我做得对吗?有人请为一个简单的问题解释为什么这么多的管理开销 . 3种写长度的方法? “长度”“长度”和“field_length” . 天哪,但这是他们显然希望你做事的方式 .

Rectangle类:创建一个Rectangle类 . 该类具有属性长度和宽度,每个属性默认为1.它具有只读属性,用于计算矩形的周长和面积 . 它具有长度和宽度的属性 . set访问器应验证长度和宽度是否都是大于0.0且小于20.0的浮点数 . 写一个应用程序来测试类Rectangle .

using System;

class Rectangle
{
private double field_length = 1;
private double field_width = 1;

public Rectangle(double Length, double Width)
{
    length = Length;
    width = Width;
}

public double length
{
    get { return field_length; }
    set { if((length>=0)&&(length<=20))
        field_length = value; }
}

public double width
{
    get { return field_width; }
    set { if((width>=0)&&(width<=20))
        field_width = value; }
}

public double Perimeter
{
    get { return 2 * field_width + 2 * field_length; ;}
    set { Perimeter = 2 * field_width + 2 * field_length; }
}

public double Area
{
    get { return field_length * field_width; }
    set { Area = field_width * field_length; }
}
}


using System;

class Program
{
    static void Main(string[] args)
    {

        Rectangle rect1 = new Rectangle(5, 6);
        Console.WriteLine(rect1.length);
        Console.WriteLine(rect1.width);
        Console.WriteLine(rect1.Perimeter);
        Console.WriteLine(rect1.Area);

        Console.ReadLine();
    }
}

1 回答

  • 6

    让我们一步一步......

    创建一个类Rectangle .

    简单:

    public class Rectangle { }
    

    该类具有属性长度和宽度

    我从上下文中假设这些是公开的:

    public class Rectangle
    {
        public double Length { get; set; }
        public double Width { get; set; }
    }
    

    但是,作为一个更高级的概念练习,我建议您也查看私有的setter并使对象不可变 . 像这样听起来它可以很好地表示为值类型,因此结构或某些不可变对象听起来更适用 . 但我离题了......

    每个默认为1 .

    当然,这是构造函数的工作:

    public class Rectangle
    {
        public double Length { get; set; }
        public double Width { get; set; }
    
        public Rectangle()
        {
            Length = 1.0;
            Width = 1.0;
        }
    }
    

    它具有只读属性,用于计算矩形的周长和面积 .

    这里的关键是“只读” . 所以这些属性只有getter并在运行中计算:

    public class Rectangle
    {
        public double Length { get; set; }
        public double Width { get; set; }
    
        public double Perimeter
        {
            get { return (2.0 * Length) + (2.0 * Width); }
        }
    
        public double Area
        {
            get { return Length * Width; }
        }
    
        public Rectangle()
        {
            Length = 1.0;
            Width = 1.0;
        }
    }
    

    它具有长度和宽度的属性 .

    很好,我早先猜对了!否则我不得不重构一下 . 但看起来这已经很满足了 .

    set访问器应验证长度和宽度是否都是大于0.0且小于20.0的浮点数 .

    现在进行一些重构 . 自动实现的属性赢得了't suffice anymore and need to become manual properties. Let'的开头:

    public class Rectangle
    {
        private double length;
        public double Length
        {
            get { return length; }
            set { length = value; }
        }
    
        private double width;
        public double Width
        {
            get { return width; }
            set { width = value; }
        }
    
        public double Perimeter
        {
            get { return (2.0 * Length) + (2.0 * Width); }
        }
    
        public double Area
        {
            get { return Length * Width; }
        }
    
        public Rectangle()
        {
            Length = 1.0;
            Width = 1.0;
        }
    }
    

    在那里,现在我们可以添加验证:

    public class Rectangle
    {
        private double length;
        public double Length
        {
            get { return length; }
            set
            {
                if ((value <= 0.0) || (value >= 20.0))
                    throw new ArgumentException("Length must be greater than 0.0 and less than 20.0");
                length = value;
            }
        }
    
        private double width;
        public double Width
        {
            get { return width; }
            set
            {
                if ((value <= 0.0) || (value >= 20.0))
                    throw new ArgumentException("Width must be greater than 0.0 and less than 20.0");
                width = value;
            }
        }
    
        public double Perimeter
        {
            get { return (2.0 * Length) + (2.0 * Width); }
        }
    
        public double Area
        {
            get { return Length * Width; }
        }
    
        public Rectangle()
        {
            Length = 1.0;
            Width = 1.0;
        }
    }
    

    我认为这涵盖了它 . 作为个人偏好的问题,您可以放弃构造函数并在线设置默认值,因为我们在一个地方都是're using private members instead of auto-implemented properties. Personally I prefer keeping that stuff in the constructor just so it' . (此外,随着对象的复杂性增加,在内联构造中放置太多逻辑会导致很难调试异常 . )

    编写应用程序以测试类Rectangle .

    app ?感叹你的导师应该感到羞耻 . 这是 unit tests 的工作!这个测试非常简单,and should actually have been written first .

    我们要测试什么?让我们从默认值开始:

    [TestMethod]
    public void RectangleHasDefaults()
    {
        // arrange
        var rectangle = new Rectangle();
    
        // act
        //  no action to perform
    
        // assert
        Assert.AreEqual(1.0, rectangle.Length);
        Assert.AreEqual(1.0, rectangle.Width);
    }
    

    这很容易,它向我们介绍了标准的arrange / act / assert模式,它应该是自动化测试的常见模式 . 让我们继续计算属性:

    [TestMethod]
    public void RectangleHasPerimeter()
    {
        // arrange
        var rectangle = new Rectangle();
    
        // act
        rectangle.Length = 2.0;
        rectangle.Width = 3.0;
    
        // assert
        Assert.AreEqual(10.0, rectangle.Perimeter);
    }
    
    [TestMethod]
    public void RectangleHasArea()
    {
        // arrange
        var rectangle = new Rectangle();
    
        // act
        rectangle.Length = 2.0;
        rectangle.Width = 3.0;
    
        // assert
        Assert.AreEqual(6.0, rectangle.Area);
    }
    

    看起来唯一要测试的是异常情况 . 根据测试框架,有多种方法可以测试异常 . (并且它们对代码覆盖率指标有不同的,有时令人愤怒的影响 . )因为我在这里假设MSTest,所以我们坚持下去:

    [TestMethod]
    [ExpectedException(typeof(ArgumentException))]
    public void LengthHasMinimum()
    {
        // arrange
        var rectangle = new Rectangle();
    
        // act
        rectangle.Length = 0.0;
    
        // assert
        //  nothing to assert
    }
    
    [TestMethod]
    [ExpectedException(typeof(ArgumentException))]
    public void LengthHasMaximum()
    {
        // arrange
        var rectangle = new Rectangle();
    
        // act
        rectangle.Length = 20.0;
    
        // assert
        //  nothing to assert
    }
    

    为简洁起见,我将省略 Width 的相同测试,你可以添加那些:)

    一旦完成所有这些,您可以重构以减少一些重复 . 's up to you. There'经常在代码之间保持 balancer ,这在语义上是不同的 . 例如,很多这些测试非常相似,尽管它们测试的是截然不同的东西 . 我建议保持语义分离,直到有充分的理由去进行重复数据删除工作 . 毕竟,重复的代码通常比错误的抽象更好 .

相关问题