简体   繁体   English

C# 中的 Class 构造函数

[英]Class constructor in C#

I am somewhat of a C# noob, and have been looking around in documentation but have been unable to understand how to create a constructor method for my class as I would in python.我有点像 C# 菜鸟,并且一直在查看文档,但无法理解如何像在 python 中那样为我的 class 创建构造函数方法。

Say I have a class named Vehicle, and when I create an instance of vehicle, I need to input the number of wheels and the number of axles the vehicles has.假设我有一个名为 Vehicle 的 class,当我创建一个车辆实例时,我需要输入车辆的轮数和车轴数。 I want the constructor to divide the total wheels by the total axles to set the property wheelsPerAxle:我希望构造函数将总轮数除以总轴数来设置属性wheelsPerAxle:

public class Vehicle
{
    public int numWheels;
    public int numAxles;
    public int wheelsPerAxle;

    public Vehicle()
    {
        wheelsPerAxle = Mathf.CeilToInt(numWheels/numAxles);
    }

}

My code example is a little ridiculous but hopefully you get the idea that I want to call the method when the object is instantiated.我的代码示例有点荒谬,但希望您明白我想在实例化 object 时调用该方法。 How can I do this?我怎样才能做到这一点?

Let's go over first what actually happens with your code, so we can get an idea of how it works.让我们先看看你的代码实际发生了什么,这样我们就可以了解它是如何工作的。

We'll use this code to make an instance of the class:我们将使用此代码创建 class 的实例:

var vehicle = new Vehicle();

// set the items inside
vehicle.numWheels = 4;
vehicle.numAxles = 2;

Well, what does this do?好吧,这有什么作用?

When code execution runs, it starts by running your constructor, and all the code inside it , before running the last two lines to modify the properties 1 .当代码执行运行时,它首先运行您的构造函数以及其中的所有代码,然后运行最后两行来修改属性1 Your object must be fully instantiated before you can modify it.您的 object 必须完全实例化,然后才能对其进行修改。

Problem is, you'll never be able to fully instantiate the object.问题是,您永远无法完全实例化 object。

Your class has two variables which you read from in the constructor, numWheels and numAxles .您的 class 有两个变量,您可以在构造函数numWheelsnumAxles中读取它们。 Both of these are (32 bit) integeters, and are uninstantiated - meaning you never directly assign them a value before you read from them.这两个都是(32 位)整数,并且没有实例化——这意味着在读取它们之前你永远不会直接为它们赋值。

However, int types are Value Types in c#, which means they are never uninstantiated .但是, int类型是c#中的值类型,这意味着它们永远不会被实例化。 If you don't set a value when you create the variable it will take the default value for that type, which in this case is 0 .如果您在创建变量时未设置值,它将采用该类型的默认值,在本例中为0

And then you try to do 0/0 , and an exception will be thrown.然后你尝试做0/0 ,会抛出异常。


The issue here is that you need to provide a value for your variables during creation of the class , as doing so afterwards is too late.这里的问题是您需要在创建 class 期间为您的变量提供一个值,因为之后这样做为时已晚。 The good news is that you can pass in values as arguments to the class's constructor.好消息是您可以将值作为 arguments 传递给类的构造函数。

public class Vehicle
{
    public int wheelsPerAxle;

    public Vehicle(int numWheels, int numAxels)
    {
        wheelsPerAxle = Mathf.CeilToInt(numWheels/numAxles);
    }
}
var vehicle = new Vehicle(4, 2);
// "vehicle.wheelsPerAxel" is 2

Note: this doesn't do any validation, and it doesn't save (scope-wise) the values for use outside of the constructor, but this should get the point across.注意:这不会进行任何验证,并且不会保存(范围方面)在构造函数之外使用的值,但这应该可以理解。

See Pac0's answer for a more robust solution to modifying your class.有关修改 class 的更强大的解决方案,请参阅 Pac0 的答案。


1 These are not properties, they are fields . 1这些不是属性,它们是字段

You can pass the parameters you need in the constructor.您可以在构造函数中传递您需要的参数。

Also, it's usually more safe to mark those fields initilized during construction as readonly if you know they can't change for a specific instance.此外,如果您知道它们无法针对特定实例进行更改,则将在构造期间初始化的那些字段标记为readonly通常更安全。 (And in this case they must be assigned a value in the constructor. (在这种情况下,它们必须在构造函数中分配一个值。

public class Vehicle
{
    public readonly int numWheels;
    public readonly int numAxles;
    public readonly int wheelsPerAxle;

    public Vehicle(int numWheels, int numAxles)
    {
        // let's do some validation here
        if (numWheels < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(numWheels), "number of wheels must be non negative");
        }
        // And do something similar for number of axles

        //set the readonly fields, if you need them for another thing later
        this.numWheels = numWheels; // We must use "this" to refer to the fields to disambiguate between the field and the parameter because I chose to give them the same name. 
        this.numAxles = numAxles;

        // I'll let you handle the case where "numAxles" is zero. Maybe you allow it ? (in this case you can use a conditional operator), or throw an exception during validation if you don't allow it.
        wheelsPerAxle = Mathf.CeilToInt(numWheels/numAxles);
    }

}

Then you can instantiate like this, calling the constructor with the proper arguments as any method:然后您可以像这样实例化,使用适当的 arguments 作为任何方法调用构造函数:

var car = new Vehicle(numWheels: 4, numAxles: 2); // Argument names are not mandatory, but good to avoid confusion while coding, since they are both int, you might invert them without noticing)

Also, here I used fields, as you did, but you can set properties as well.另外,在这里我使用了字段,就像你一样,但你也可以设置属性。 And auto-properties if you want.如果你愿意,还有自动属性。 To make them readonly, just give them a get;要使它们只读,只需给它们一个get; , instead of get; set; , 而不是get; set; get; set;

You mentioned Property, but what you have there are fields.您提到了属性,但是您拥有的是字段。 Please read this answer to understand the difference.请阅读此答案以了解其中的区别。 So I assumed that you really need property in my code:所以我假设你真的需要我的代码中的属性:

The first solution is assuming that WheelsPerAxle is readonly property.第一个解决方案是假设WheelsPerAxle是只读属性。

public class Vehicle
{
    public int NumWheels { get; set; }
    public int NumAxles { get; set; }

    //if you want to have it as readonly
   public int WheelsPerAxle => Mathf.CeilToInt(NumWheels / NumAxles);

    public Vehicle(int numWheels, int numAxles)
    {
        NumWheels = numWheels;
        NumAxles = numAxles;
    }

}

and second solution is assuming WheelsPerAxle has a setter第二个解决方案是假设WheelsPerAxle有一个设置器

public class Vehicle
{
    public int NumWheels { get; set; }
    public int NumAxles { get; set; }

    //if you want to set it later on and change its value
    public int WheelsPerAxle { get; set; }

    public Vehicle(int numWheels, int numAxles)
    {
        NumWheels = numWheels;
        NumAxles = numAxles;
        WheelsPerAxle = Mathf.CeilToInt(NumWheels / NumAxles);
    }

}

Make sure to add some validations.确保添加一些验证。

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

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