Click here to Skip to main content
15,890,438 members
Please Sign up or sign in to vote.
1.80/5 (2 votes)
See more:
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.

C#
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();
    }
}
Posted
Updated 9-Nov-13 3:26am
v2
Comments
Sergey Alexandrovich Kryukov 9-Nov-13 20:04pm    
"Real-time development" is the absurdity. Never say words you don't understand, just because you think they sound "clever".
—SA

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 , ... ) ;
}


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.
 
Share this answer
 
v2
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:
C#
// 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;
}
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.
 
Share this answer
 
v2
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:
C#
public Student() { }
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.
 
Share this answer
 
In fact, if you don't have data that should be kept as "immutable" and must be initialized by the user of your type, there's no need for a constructor at all.

The constructor is useful to initialize data that you expect to be there from the first access to the created instance, be it data that's received as parameter and kept as read-only or be it data that you will initialize by your own. In fact, except for threading or performance concerns, it is usually preferable to allow the instance to be created "empty" and then filled, but this forces all the methods that may use the filled properties to check if they have valid values.

But, if you receive all the needed parameters and do the validation in the constructor, then you can keep your instance read-only and all methods may avoid verifying if the instance was correctly filled, as it should be (or else the constructor will have failed).
 
Share this answer
 
I am not sure if anyone addressed the main problem so far: the access to class members without construction of the instance of the class is absolutely unrelated to the access modifiers (public, private, etc.). All members can be either static, or non-static, and non-static members are also called "instance members". Instance members are per-instance, so they all need an instance of the class. And static members do not need an instance.

Please see my past answers:
C# windows base this key word related and its uses in the application[^],
What makes static methods accessible?[^].

—SA
 
Share this answer
 
We use the new operator when instantiating instances of a class. You must combine the new operator with the type name and its constructor arguments to create a new instance of the type. You can use any constructor available.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 9-Nov-13 20:06pm    
You see, all the words are correct, the only problem is: they don't address the OP's problem, which is based on some deep misunderstanding...
—SA
Hi
The following links have some codes and text about what you want, I have read them and it is useful to understand the matter.

http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html

and

http://stackoverflow.com/questions/7552964/what-is-best-way-to-share-class-instance-create-and-share-singleton

best regards
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900