参数未知的构造函数

时间:2015-09-30 17:07:43

标签: c# class oop inheritance constructor

我最近开始在C#中开始做一些编程,之后我大部分时间都在PHP

PHP我可以这样做:

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

但是,在C#我似乎没有这种可能性,因为在它进入第一个构造函数之前我似乎必须知道$UserId

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.
    }
}

有没有办法在C#中实现我想要做的事情?

基本上将值传递给主对象的构造函数,主对象在自己的主体中指出要传递给基类的值。

6 个答案:

答案 0 :(得分:6)

您可以在构造函数中调用静态方法。虽然非常不标准。

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;
    }
}

答案 1 :(得分:4)

关注点分离

其他答案未能理解的是PHP和C#具有非常不同的编码标准。

PHP中的常见模式是

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

但这绝对不会被认为是C#中的好设计。

在.net中实现此功能的典型方法将更接近

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

关键是可以想象员工在没有数据库的情况下使用,例如在单元测试中。

答案 2 :(得分:3)

您可以重构共享功能:

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

请注意,我将参数名称的大小更改为更标准的低驼峰大小写。

  

我以前做的是将Id(我的db表中的主键)传递给对象构造函数,然后从构造函数中的db中获取数据。

不要这样做。类不应该依赖外部数据源来创建自己的实例。创建一个单独的类(存储库,工厂,等等),从数据库中提取数据并填充空白对象的属性。

将数据库逻辑放在类的构造函数中会阻止独立于数据源的测试。

答案 3 :(得分:1)

如何使用静态方法实例化您的类?

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

然后在你的调用代码中你会:

var employee = Employee.GetEmployee(someValue);

答案 4 :(得分:0)

某些语言允许您从派生构造函数中显式调用基础构造函数。

C#不是这样的语言。

在这种情况下,由于EmployeeId与UserId不同并且在派生类构造函数中计算,因此您必须从Employee构造函数设置它,而不是将其作为参数传递给基类构造函数。

UserId的基类中的后备存储需要设置为protected,或者您需要提供受保护的属性或方法来设置它。

答案 5 :(得分:0)

您不想做的事情(并且可能不应该 - 感谢,PHP)可能,但这样的事情应该足够了:

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