lshas
lshas

Reputation: 1731

Constructor with unknown argument

I have recently started to do some programming in C#, after spending most of my life in PHP.

In PHP I could do this:

class User
{
    public __construct($UserId)
    {
        // Do stuff
    }
}

class Employee extends User
{
    public __construct($EmployeeId)
    {
        // Look up the UserId connected to $EmployeeId
        $UserId = hypothetical_get_user_id_func($EmployeeId);
        parent::__construct($UserId);
    }
}

But, in C# I don't seem to have that possibility, since it seems like I must know the $UserId before it enters the first constructor.

public class User
{
    public User(int UserId)
    {
        // Do stuff
    }
}

public class Employee : User
{
    public Employee(int EmployeeId) : base(***) // I don't know this value yet?
    {
        // This is where I would find the User Id, and would like to pass
        // it to the User class constructor.
    }
}

Is there any way to achieve what I am trying to do here in C#?

Basically passing a value to the constructor of the main object, which in its own body figures out what value to pass to the base class.

Upvotes: 0

Views: 298

Answers (6)

D Stanley
D Stanley

Reputation: 152521

You'll could refactor to a shared function:

public class User
{

    protected User() {}

    public User(int userId)
    {
        Init(userId);
    }

    protected void Init(int userId)
    {
        // Do stuff
    }

}

public class Employee : User
{
    public Employee(int employeeId)  
    {
        // find user Id here

        Init(userId);
    }
}

Note that I changed the casing of your parameter names to the more standard lower-camel-case.

What I am used to doing is to pass the Id (primary key in my db table), to the object constructor, and then fetch the data from the db in the constructor.

Don't do that. Classes should not have to rely on an external data source to create instances of themselves. Create a separate class (repository, factory, whatever) that pulls the data from the database and populates the properties of the blank objects.

Putting database logic in the constructor of a class prevents testing independent of the data source.

Upvotes: 3

DVK
DVK

Reputation: 2792

How about using a static method to instantiate your class?

public class User
{
    public User(int UserId)
    {
        // Do stuff
    }
}

public class Employee : User
{
    private Employee(int userID) : base(userID) { }

    public static Employee GetEmployee(int employeeID)
    {
        var userID = GetUserIDFromEmployeeID(employeeID);

        return new Employee(userID);
    }
}

Then in your calling code you would:

var employee = Employee.GetEmployee(someValue);

Upvotes: 1

Aron
Aron

Reputation: 15772

Separation of Concern

What the other answers have failed to understand is that PHP and C# have very different coding standards.

A common pattern in PHP would be

class User
{
    public __construct($UserId)
    {
        // Do stuff
    }
}

class Employee extends User
{
    public __construct($EmployeeId)
    {
        // Look up the UserId connected to $EmployeeId
        $UserId = get_userid_from_database($EmployeeId);
        parent::__construct($UserId);
    }
}

But this is absolutely never going to be recognised as being a good design in C#.

The typical way to implement this in .net would be much closer to

public class User
{
    public User(int userId)
    {
        // Do stuff
    }
}

public class Employee : User
{
    public Employee(int employeeId, int userId) : base(userId) // I don't know this value yet?
    {
        // This is where I would find the User Id, and would like to pass
        // it to the User class constructor.
    }
}

public class EmployeeRepository
{
    public Employee GetEmployee(int employeeId)
    {
        using(var connection = new SqlConnection(..)
        {
            //blah blah blah
            return new Employee(employeeId, userId);
        }
    }
}

The point being that Employee might be conceivably used without a database, for example in a unit test.

Upvotes: 4

Loofer
Loofer

Reputation: 6965

You can call a static method in a constructor. Very non standard though.

public class User
{
    public User(int userId)
    {
        // Do stuff
    }
}

public class Employee : User
{
    public Employee(int employeeId) : base(GetUserId(employeeId))
    {

    }

    public static int GetUserId(int employeeId)
    {           
        return employeeId - 5;
    }
}

Upvotes: 6

funbrigade
funbrigade

Reputation: 321

What you'd like to do isn't (and probably shouldn't be -- thanks, PHP) possible, but something like this should suffice:

public class User
{
    protected User() {
        // Do things here
    }

    public User(int UserId)
    {
        Init(UserId);
    }

    protected void Init(int UserId) {
        // Do stuff
    }
}

public class Employee : User
{
    public Employee(int EmployeeId) : base()
    {
        int UserId;
        // Find UserId

        Init(UserId);
    }
}

Upvotes: 0

Eric J.
Eric J.

Reputation: 150108

Some languages allow you to explicitly call a base constructor from within a derived constructor.

C# is not such a language.

In this case, since EmployeeId is not the same thing as UserId and is calculated in the derived class constructor, you will have to set it from the Employee constructor rather than pass it as a parameter to the base class constructor.

The backing storage in the base class for UserId needs to be set as protected, or you need to provide a protected property or method to set it.

Upvotes: 0

Related Questions