简体   繁体   中英

Passing object of class in constructor of the same class

How do you initialize a class like this with say StudentId = 1 and Name = "Alex"

class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    public Student(Student student)
    {
        StudentId = student.StudentId;
        Name = student.Name;
    }
}
class Program
{
    static void Main(string[] args)
    {
        Student s = new Student()
    }
}

You can add another constructor in which you supply values manually:

public Student(int id, string name)
{
    StudentId = id;
    Name = name;
}

The reason your initial code doesn't work is, when you are creating an object that needs another instance of the same type, the dependency chain goes up to infinity and you can never have a start point.

By having a manual constructor, you can manually create a start point, in other words, an initial object that other objects can depend on. Therefore you eliminate infinite dependency chain.

You cannot initialize a class like that: it requires an instance of itself in order to be initialized, presenting a chicken-and-egg problem.

Note that you cannot construct a derived class and pass it to Student 's constructor, because the derived class would have to call the copy constructor.

The only way around this issue is to add a constructor other than the one you have, and call it:

public Student(int id, string name) {
    StudentId = id;
    Name = name;
}

or to add a default constructor, and call it with property initializers:

public Student() {}
...
var student = new Student {Id = 1, Name = "Alex" };

It doesn't really make sense to have the only constructor for a class require an instance of the class, and you would definitely need some other type of constructor in order to use one (otherwise you can never create that initial instance).

One thing that does make sense, however, is to have a static method that creates a new instance of the class from an existing class.

The example below does not have any explicit constructor defined, so the default constructor is used and the class values are set explicitly:

class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    public static Student CreateFrom(Student student)
    {
        return new Student { StudentId = student.StudentId, Name = student.Name };
    }
}

To use this method, you would first create a student:

var studentOne = new Student { StudentId = 1, Name = "Bob"};

Then, to create a new student from this one, we can call our static method:

var studentTwo = Student.CreateFrom(studentOne);

But now we have two students with the same Id. Perhaps that's not really what we want, so it might be better to have an read-only StudentId that gets set automatically from a private static backing field. We can use a lock object to ensure we don't assign the same id to more than one student. Also we can override the ToString method so it displays the Id and Name of the student:

class Student
{
    // This lock object is used to ensure we don't 
    // assign the same Id to more than one student
    private static readonly object IdLocker = new object();

    // This keeps track of next available student Id
    private static int nextStudentId;

    // Read only
    public int StudentId { get; }

    public string Name { get; set; }

    // Default constructor automatically sets the student Id
    public Student()
    {
        lock (IdLocker)
        {
            // Assign student id and incrment the next avaialable
            StudentId = nextStudentId;
            nextStudentId++;
        }
    }

    public static Student CreateFrom(Student student)
    {
        return new Student { Name = student.Name };
    }

    public override string ToString()
    {
        return $"Student {StudentId}: {Name}";
    }
}

Now we don't need to set the id, and we can see that it automatically increments for us:

private static void Main()
{
    var studentOne = new Student { Name = "Bob" };
    var studentTwo = Student.CreateFrom(studentOne);

    Console.WriteLine(studentOne);
    Console.WriteLine(studentTwo);

    Console.Write("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

Output

在此输入图像描述

You need some way of initializing the object without that constructor. So using a default constructor with inline initialization to create the initial student, then lets you create other Student objects using already existing instances of it.

using System;

public class Program
{
    public static void Main()
    {
        var s = new Student {
            StudentId = 1,
            Name = "Alex"
        };

        var s2 = new Student(s);

        Console.WriteLine(s2.StudentId);
        Console.WriteLine(s2.Name);
    }
}

class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    public Student() {}

    public Student(Student student)
    {
        StudentId = student.StudentId;
        Name = student.Name;
    }
}

DotNetFiddle

Your code is confusing, you just need to pass in constructor the parameters instead of an object, but the way you are trying to do, you would need to set first properties on the instance created in Main program and then pass the instance like, but you will also need to add a parameter-less constructor too:

class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    // Note: parameterless constructor here
    public Student()
    {


    }

    public Student(Student student)
    {
        StudentId = student.StudentId;
        Name = student.Name;
    }
}
static void Main(string[] args)
{
        Student s = new Student(); // parameter less constructor
        s.StudentId = 1;
        s.Name = "Alex";

       Student s2 = new Student(s);
}

But note that This will make your code compile and even work, but this is too much of extra stuff for doing simple thing and not memory efficient as there is one extra instance we have created which is not needed at all.

so you just need to have parameters in the constructor for StudentId and Name like S. Tarik's answer showed.

That way your constructor would look like:

public Student(int studentId, string name)
{
    StudentId = studentId;
    Name = name;
}

Hope it gives you the idea how to approach this problem.

Thanks!

public class Student
{ 
  public int Id {get; set;}
  public string Name {get; set; }

  public Student(object o) 
  {
    Student student = o as Student;
    if (student != null)
    {
       Id = student.Id;
       Name = student.Name;
    }

    // other cases to build a User copy
    string json = o as string;
    if (json != null) 
    {
         Student student = JsonConvert.Deserialize<Student>(json);
         Id = student.Id;
         Name = student.Name;
    }

  }

  public Student() 
      : this(null)
  {

  }

  public Student(int id, string name) 
      this(null)
  {
      Id = id;
      Name = name;
  }
}



static void Main(string[] args) 
{
     Student student = new Student(7634, "Jim");

     // build a copy
     Student copy = new Student(student);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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