繁体   English   中英

C#中的构造函数

[英]Constructors in C#

我已经阅读了很多关于为什么构造函数有用以及我发现的所有资源都指定构造函数用于初始化类的实例的信息。 使用构造函数的一个主要好处是它可以保证对象在使用前经过适当的初始化,通常接受参数。 它有助于确保对象的完整性,并使使用面向对象语言编写的应用程序更加可靠。

默认情况下,如果在类中未指定构造函数,则在 C# 中会实例化默认的空构造函数。

我发现的大多数示例都指定了这样的内容;

public Car(int speedCurrent, int gearCurrent) {
    speed = speedCurrent;
    gear= startGear;
}

Car myCar = new Car(0, 0);

现在,当您可以指定属性时,创建构造函数的实际意义是什么?

public int speed { get; set; }
public int gear { get; set; }

并像这样初始化它;

Car myCar = new Car();
myCar.speed = 0;
myCar.gear = 0;

我无法满足明确创建构造函数的需要。 如果有人能给我一个很好的实际例子,我将不胜感激。

虽然您可以像您显示的那样初始化属性:

Car myCar = new Car();
myCar.speed = 0;
myCar.gear = 0;

如果没有构造函数,您也可以选择初始化任何属性

Car myCar = new Car();

这可能会导致班级工作不佳/根本无法工作。

构造函数的目的是强制您在允许使用类实例之前初始化所有必需的属性(按设计)。

如果您考虑在具有多个团队成员的项目中工作的情况,这将特别有用。 如果您的团队成员想要使用您的class ,通过拥有正确的构造函数,您已经可以向他们提示需要在class中初始化哪些属性以便他们正确使用类。

现在,当您可以指定属性时,创建构造函数的实际意义是什么?

拥有非默认构造函数的好处是您必须将所有必需的依赖项传递给它。 这保证了当实例化时,对象将拥有它正常运行所需的一切。

现在当您可以指定属性时创建构造函数的实际意义是什么

公开属性的方法有四个问题:

  • 初始化后无法确保一致性——例如,如果要确保非零速度需要非零档位,则不再可以控制此检查
  • 当必须以原子方式更新多个属性时,您无法确保一致性- 在必须同时更新speedgear并发情况下,由锁保护的独立公开属性的方法将不可靠
  • 你被迫使你的对象可变- 这并不总是可取的,特别是当你的对象是为并发使用而设计的
  • 您被迫公开用户可能不需要的方法- 即使在您的用户期望可变对象的情况下,也可能不希望公开单个 setter; 使用这种方法,您别无选择。

我无法满足明确创建构造函数的需要。

以下是当您的 setter 未公开时您可以做什么的简短演示:

class Car {
    private readonly object lockObject = new object();
    private int speed;
    private int gear;
    public int Speed {
        lock (lockObject) {
            return speed;
        }
    }
    public int Gear {
        lock (lockObject) {
            return gear;
        }
    }
    public int Gear{ get; }
    public Car(int speed, int gear) {
        // You can validate two attributes together
        if (speed != 0 && gear == 0) {
            throw new ArgumentException("Non-zero speed in zero gear");
        }
        this.speed = speed;
        this.gear= gear;
    }
    public void SpeedUp(int increase) {
        lock(lockObject) {
            var newSpeed = Math.Max(Speed + increase, 0);
            if (newSpeed > 200) {
                 throw new InvalidOperationexception("Cannot speed up past 200");
            }
            // Concurrent users would not see inconsistent speed setting
            Speed = newSpeed;
            Gear = Speed / 25;
        }
    }
}

主要优点是您能够在并发环境中同时进行调整,以及一种确保初始对象一致性的方法。

你的例子中的实际点是你不需要做一个new Car(0, 0); 用于实例化,而只是为默认初始化执行此操作:

public Car() {
    speed = 0;
    gear = 0;
}

Car myCar = new Car();

非默认构造函数强制您的类的客户端提供参数。 代码不需要通过属性 a) 初始化 b) 可以公开尚未准备好使用的类。 此外,您可能想对其他人隐藏速度或齿轮属性。

根据您的类的作用,您可能需要进行一些初始化。 例如,一个类可能会在初始化时钩住一个静态事件,或者输出到调试......在编码时它也给了你一个点,你可以设置一个断点来在任何尝试实例化类时中断。

问题是 Car 类的用户需要以某种方式知道他们需要设置汽车的初始速度和档位。

我遵循的规则准则是构造函数应该创建一个 100% 可以使用的对象。

构造函数的概念很老派。 回到 C 和 C++ 时代,当您自己管理所有指针时。 构造函数将设置大部分可空变量,以确保您在执行代码时不会遇到一般保护错误或分段错误。

现代编码人员避免使用带参数的构造函数。 这是由于它们在执行自动化单元测试时造成的困难。 使用只有默认构造函数(没有参数的构造函数)的类并在事后调用属性或方法来初始化它们是完全可以的。

我会说这归结为您希望如何实现您正在构建的课程的目标。

在 OO Programming 中实现封装,您只能通过 getter/setter 访问成员。 同样,这取决于您想在实现 OO 原则方面走多远。

何时应该将变量传递给构造函数的一个例子是,如果构造函数中有一些需要这些值的初始化代码。

private int speed { get; set; }
private int gear { get; set; }
private bool reduceSpeed { get; set; }

public Car(int speedCurrent, int gearCurrent) {
    speed = speedCurrent;
    gear= startGear;
    if (speed > 30)
        reduceSpeed = true; // do further processing with this.
    ...
}

C# 中的构造函数:(简单的理论)

  • 是一种特殊类型的函数/方法,与它的类同名。
  • 每当创建类的对象时都会自动调用它。
  • 它还负责其类成员的对象初始化和内存分配。
  • 它没有返回类型,甚至没有空类型。
  • 支持使用参数化构造函数进行重载。

它们有 4 种类型:

在此处输入图片说明

默认构造函数:

默认构造函数没有参数。 当一个类没有构造函数时,编译器会为该类提供默认构造函数。 如果您没有定义任何构造函数,则默认构造函数由编译器定义。 它用于为类的实例变量分配默认值

示例:

namespace Default_parameterizedConstructor
{
    public class Student
    {
        // instance members
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string College { get; set; }

        //default constructor parameters less
        public Student()
        {
            College = "My College"; //explicit default value for college
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Object instance of Student.
            Student st = new Student();
            Console.WriteLine("Student details are Student ID: {0}, Student Name: {1}, College :{2}", st.StudentId, st.Name, st.College);
            Console.ReadKey();
        }
    }
}

默认构造函数的输出将是:“学生详细信息是学生 ID:0,学生姓名:,学院:我的学院”

参数化构造函数:参数化构造函数具有一个或多个参数。 当我们必须传递一个或多个参数时使用,以便我们可以设置类实例成员的参数。 用于为类的实例变量赋值。 当实例成员名称和构造函数接收参数相同时,我们使用 this 关键字,在这种情况下,必须指定 this 关键字。 如果名称不同,则可以选择使用此关键字。

现在,让我们以参数化构造函数为例:

namespace Default_parameterizedConstructor
{

    public class Student
    {
        // instance members
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string College { get; set; }

        //default constructor parameters less
        public Student()
        {
            College = "My College"; //explicit default value for college
        }
        // parameterised constructor
        public Student(int studentid, string name, string college)
        {
            this.StudentId = studentid;
            this.Name = name;
            this.College = college;

        }
        public Student(int studentid, string name)
        {
            this.StudentId = studentid;
            this.Name = name;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //default constructor parameter
            //Object instance of Student.
            Student st = new Student();
            Console.WriteLine("The output for Default Constructor are Student ID: {0}, Student Name: {1}, College :{2}", st.StudentId, st.Name, st.College);
            
            
            // parameterised constructor
            //Operator overloading happening.
            Student st1 = new Student(1, "John Doe", "MIT");
            Console.WriteLine("The output for Default Constructor are Student ID: {0}, Student Name: {1}, College :{2}", st1.StudentId, st1.Name, st1.College);

            // parameterised constructor with operator overloading
            Student st2 = new Student(1,"Jimmy");
            Console.WriteLine("The output for Default Constructor are Student ID: {0}, Student Name: {1}, College :{2}", st2.StudentId, st2.Name, st2.College);

            Console.ReadKey();
        }
    }
}

*输出如下: //First

Default Constructor 的输出是 Student ID: 0, Student Name: , College :My College

//第二

默认构造函数的输出是学生 ID:1,学生姓名:John Doe,学院:MIT

//第三

默认构造函数的输出是学生 ID:1,学生姓名:Jimmy,学院:*

静态构造函数:一种特殊类型的构造函数,在创建类的第一个对象之前被调用。 用于初始化任何静态字段,或执行只需要执行一次的特定操作。 一个类只能有一个静态构造函数,并且它必须是一个默认构造函数,没有访问修饰符。

私有构造函数:限制类的外部实例化,但在嵌套类中,您可以创建此类的实例。 在 C# 1 X 中没有静态类,因此开发人员使用私有构造函数来防止类外部实例化。 用于实现单例模式,即类的单个实例。 一个类可以有多个私有构造函数和公共构造函数。

如果您不创建实例,您将如何访问该值? 我们可以通过将类的成员设置为私有静态来做到这一点。 使用类名只能使用静态成员。

让我们通过下面的例子来看看两者:

namespace StaticAndPrivate
{
    public class Example
    {
        private static int Counter;

        //private constructor
        private Example()
        {
            Counter = 10;
        }

        //static constructor
        static Example()
        {
            Counter = 20;
        }

        //public constructor
        public Example(int counter)
        {
            Counter = Counter + counter;
        }

        public static int GetCounter()
        {
            return ++Counter;
        }

        public class NestedExample
        {
            public void Test()
            {
                //internal instance
                Example ex = new Example();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //external instance
            //Example ex = new Example();

            Example ex = new Example(10);
            Console.WriteLine("Counter : {0}", Example.GetCounter());

            Console.ReadKey();
        }
    }
}

希望这可以通过一个例子来解释这个概念。

暂无
暂无

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

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