创建类/对象实例的最佳方法是什么。 [英] What is the best way of creating an instance of a class/object.

查看:67
本文介绍了创建类/对象实例的最佳方法是什么。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个类可以有私有字段,公共属性,构造函数和方法。



我在想如果我们有公共属性那么我们还需要一个构造函数在一些参数?我在这里做的方式是,在我的构造函数中,我将我的参数直接分配给公共属性而不是私有字段(我不确定这是否正常)。



这是您在实时开发中通常会做的事情吗?



(如果只是个人偏好的问题那么我喜欢使用构造函数的方式我已经在这里完成了。)



请随时发表评论并提供建议。



谢谢。



A class can have private fields, public properties, constructors and methods.

I was thinking if we have public properties then do we still need a constructor that takes in some parameters? The way I have done it here, is that in my constructor, I am assigning my parameters directly to public properties not private fields(i am not sure if this is ok).

Is that what you would normally do in a real time development?

(if its just a matter of personal preference then I like to use constructors just the way I have done it here.)

Please feel free to comment and provide suggestions.

Thank you.

class Student
{
    // private fields
    private int id;
    private string firstName;
    private string lastName;
    //private char gender;
    //private string city;

    // public properties
    public int ID
    {
        get
        {
            return id;
        }
        set
        {
            if (value <= 0)
            {
                throw new Exception("Invalid ID!");
            }
            else
            {
                id = value;
            }
        }
    }

    public string FirstName
    {
        get
        {
            return firstName;
        }
        set
        {
            if (!String.IsNullOrEmpty(value))
            {
                firstName = value;
            }
        }
    }

    public string LastName
    {
        get
        {
            return lastName;
        }
        set
        {
            if (!String.IsNullOrEmpty(value))
            {
                lastName = value;
            }
        }
    }

    // Auto properties where the compiler will automaticaly assign a provate field to these properties
    public char Gender { get; set; }

    public string City { get; set; }

    // Constructor
    public Student() { }

    public Student(int _id, string _firstName, string _lastName, char _gender, string _city)
    {
        ID = _id;
        FirstName = _firstName;
        LastName = _lastName;
        Gender = _gender;
        City = _city;
    }

    // Methods
    public void Print()
    {
        Console.WriteLine("Student {0} {1} is a {2} in {3} city.", firstName, lastName, Gender, City);
    }
}


class Program
{
    static void Main(string[] args)
    {
        Student s = new Student(11, "John", "Smith", 'm', "Boston");
        s.Print();

        Student myStudent = new Student();
        myStudent.ID = 12;
        myStudent.FirstName = "John";
        myStudent.LastName = "Smith";
        myStudent.Gender = 'm';
        myStudent.City = "Boston";
        myStudent.Print();

        Student s1 = new Student
        {
            ID = 13,
            FirstName = "ad",
            LastName = "asd",
            Gender = 'm',
            City = "Dublin"
        };
        s1.Print();

        Console.Read();
    }
}

推荐答案

我尝试遵循的一条基本规则是:一个实例一旦它被构造就应该是有用的。构造完成后的可选设置没问题,但是如果你在实例构建之前必须设置属性,那么就会出现问题。



然而,正如您可能已经注意到的,许多.net类(例如WinForms控件)不遵循此方法,而是使用无参数构造函数,然后可以设置属性。你可以编写一个Initialize方法,它接受构造函数可以采用的参数。



为什么?

0)许多.net类实现接口。不幸的是,Interfaces无法指定构造函数。但是接口可以指定Initialize方法。



1)通用约束可以指定类必须实现接口和/或具有无参数构造函数,但是它们不能指定一个类必须有一个带有某些参数的构造函数。





在你的例子中,你可以编写一个接口:



One basic rule I try to follow is: "an instance should be useful as soon as it's constructed". Optional settings after construction are OK, but if you have to set properties after construction before the instance is useful, then there's something wrong.

However, as you may have noticed, many .net classes (WinForms controls for instance) do not follow this approach and instead have a parameterless constructor and then the properties can be set. You could write an Initialize method that takes the parameters that the constructor could have taken.

Why?
0) Many .net classes implement Interfaces. Unfortunately, Interfaces cannot specify constructors. But an Interface could specify an Initialize method.

1) Generic constraints can specify that a class must implement an Interface and/or have a parameterless constructor, but they cannot specify that a class must have a constructor that takes certain parameters.


In your example, you can write an Interface:

public interface IPerson
{
  int ID { get ; set ; } ;
  string FirstName { get ; set ; } ;
  string LastName { get ; set ; } ;
  string Gender { get ; set ; } ;
  string City { get ; set ; } ;

  void Initialize ( int ID , string Firstname , ... ) ;
}





您的学生班,教师班以及任何其他合适的班级都可以实施此界面。然后,如果您需要编写需要实例化学生或其他IPerson的泛型类或方法:





Your Student class, a Teacher class, and any other suitable classes can implement this Interface. Then if you need to write a generic class or method that needs to instantiate a Student or other IPerson:

public class Importer<T> where T : IPerson , new()
{
  public T Import ( some source, maybe a database ) 
  { 
    T result = new T() ;

    result.Initialize ( id , firstname , ... ) ;

    return ( result ) ;
  } 
}







所以,你可以看到这种技术是使用具有类层次结构的泛型时相当强大。





我建议使用针对性别的枚举,而不是字符串。




So, you can see that this technique is rather powerful when using generics with hierarchies of classes.


And I'd recommend using an enumeration for Gender, rather than a string.


在.NET中使用构造函数的最佳方式是适合应用程序总体目标的方式,以及在应用程序中导入/转换/导出的数据的整体性质,如手套适合一只手:)



这就是说:有许多可能的正确方法使用Constructors for Classes(或Structs)。



一个具体的评论:你说:一个类可以有私有字段,公共属性,构造函数和方法。我不确定这需要说,但是:一个班级还可以拥有公共字段,私有属性和内部私人类。



我在代码中注意到的一件事是,在设置公共属性时执行验证。在其中一个公共属性ID中,如果输入不正确,则会抛出错误;在其他属性中你没有。



在两种情况下,性别和城市,你依赖.NET自动绑定一个属性到一个隐藏的内部变量,而不是像其他属性那样为'set和'get函数编写代码。



你是唯一能回答这些问题的人:



1.如果所有物业都以同样方式处理



2.应该全部如果出现意外或不正确的输入,属性会抛出错误吗?



3.是否在属性中处理此应用程序的正确之处?如果班级的外部消费者在运行时更改了属性,那么答案几乎肯定是是。



如果班级的消费者是<我>永远不会更改属性,然后您可以考虑在构造函数中进行验证;或者......其他地方?



我在代码中看到遗漏的一个想法是在.NET中使用链式构造函数。考虑这个摘录...... WinForms,一个UserControl ......来自我目前正在处理的代码:
The best way to use Constructors in .NET is the way that fits the overall goal of your Application, and the overall nature of the Data you import/transform/export in the Application, like a glove fits a hand :)

Which is to say: there are many possible "correct" ways of using Constructors for Classes (or Structs).

One specific comment: you state: "A class can have private fields, public properties, constructors and methods." I'm not sure this needs saying, but: a Class can also have public fields, and private Properties, and internal private Classes.

One thing I note in your code is that you perform validation when you set Public Properties. In one of the Public Properties, "ID," you throw an error in the case of incorrect input; in the other properties you don't.

In two cases, "Gender," and "City," you rely on .NET's automatic binding of a Property to a hidden internal variable, rather than write code for the 'set and 'get functions as you do for the other Properties.

You are the only one who can answer the questions:

1. should all the Properties be handled in the same way

2. should all the Properties throw an error if there's unexpected or incorrect input ?

3. is handling validation in the Properties the "right thing" for this Application ? if external "consumers" of your Class are changing the Properties at run-time, then the answer is almost certainly "yes."

if consumers of the Class are never going to change the Properties, then you might consider doing validation in the Constructor; or ... elsewhere ?

The one idea I see "missing" in your code is the use of chained Constructors in .NET. Consider this excerpt ... WinForms, a UserControl ... from code I am currently working on:
// base ctor ()
public DdwnChkCombo()
{
    InitializeComponent();
}

// second ctor (string, List<string>)
public DdwnChkCombo(string title, List<string> lvItems): this()
{
    foreach (string str in lvItems)
    {
        dDwnListView.Items.Add(new ListViewItem(str));
    }
    dDwnButton.Text = title;
}

// third ctor (string, List<string>, int)
public DdwnChkCombo(string title, List<string> lvItems, int width): this(title, lvItems)
{
    this.Width = width;
}

如果上面的第三个ctor用于创建'DdnChkCombo的新实例,则以下序列将在运行时发生:



1.第三个ctor被调用,但其body中的代码未被执行:控制流被传递给第二个ctor。



2.第二个ctor ...因为下一个ctor是无参数的...将导致控制流进入类中私有字段的初始化。有趣的是,接下来将执行Designer.cs类的一部分,其中设置了'components变量。



3.控制进入第一个ctor,并执行Designer.cs文件中的InitializeComponents,用于构建/布局表单及其控件。



4.然后控制权传递回第二个ctor,并执行其正文中的代码。



5.最后,控制移动到第三个ctor,并执行其正文中的代码。



所以,你有一种方法可以定义多个构造函数,在这些构造函数中你连续添加更多参数,并在参数列表之后使用特殊运算符this,前面是冒号,为您提供了一种逐步构建类的方法。



当然,总有其他方法:您可以为类定义可选参数:但是,如果您这样做当然,你必须写一些布尔测试,看它们是否存在,或者缺席。



我建议你在开发Classes和试验继承时,养成使用Visual Studio中的调试器逐步执行代码的习惯,并观察确切地说,当实例化类时会发生什么。

If the third ctor above is used to make a new instance of 'DdnChkCombo, the following sequence will occur at run-time:

1. the third ctor is called, but the code in its "body" is not executed: flow-of-control is passed to the second ctor.

2. the second ctor ... because the next ctor is parameterless ... will result in flow-of-control going to initialization of the private fields in the class. interestingly, this will be followed by execution of one part of the Designer.cs Class where the 'components variable is set.

3. control goes to the first ctor, and InitializeComponents in the Designer.cs file is executed which builds/lays-out the Form and its Controls.

4. then control is passed back to the second ctor, and the code in its body is executed.

5. finally, control moves to the third ctor, and the code in its body is executed.

So, you have a way of defining multiple constructors, in which you successively add more parameters, and the use of the special operator "this" after the parameter list, preceded by a colon, gives you a way to incrementally build your Classes.

Of course, there are always other ways: you could define optional parameters for a Class: but, if you do that, then you, of course, have to write some boolean tests to see if they are present, or absent.

I recommend that as you develop Classes, and experiment with inheritance, you make a habit of stepping-through your code using the debugger in Visual Studio, and observing exactly what happens as Classes are instantiated.


这在某种程度上是个人的事情,但它可以用来确保一个类从构造的那一刻起就完成了。

如果删除默认构造函数:

It's a personal thing to an extent, but it can be used to ensure that a class is complete from the moment it is constructed.
If you delete the default constructor:
public Student() { }

然后构造实例的唯一方法是通过带参数的版本 - 这意味着在没有有效值的情况下无法创建类。



我个人使用什么?这取决于。通常,我使用默认构造函数来创建一个全新的实例,并使用参数化版本来从我从数据库中读取的现有数据构造实例。这种方法的一个优点是,设置类的值可以绕过属性并直接转到支持字段 - 这意味着没有为现有值设置任何IsDirty标志,这意味着它们不会被处理不必要地修改并写回数据库。



作为一般规则,我尝试直接访问支持字段:如果没有别的话,它可以节省处理时间作为调用属性访问归结为的方法被保存。

Then the only way to construct the instance is via the version with parameters - which means that the class cannot be created without "valid" values in place.

What do I use personally? It depends. Quite often, I use a default constructor to create a completely new instance, and a parameterized version to construct an instance from existing data that I have read from a database, for example. One of the advantages for me of this approach is that setting the values of the class can bypass the Properties and go direct to the backing fields - which means that any IsDirty flag isn't set for existing values which means they don't get treated as modified and written back to the DB unnecessarily.

As a general rule, I try to access backing fields directly where I can: if nothing else, it saves processing time as the method call that a property access boils down to is saved.


这篇关于创建类/对象实例的最佳方法是什么。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆