【问题标题】:Parameterized Constructor requires reference to project参数化构造函数需要引用项目
【发布时间】:2015-11-24 04:47:20
【问题描述】:

不确定标题是否准确代表我的问题,对此感到抱歉。

我有三个项目:持久性、核心(逻辑)和测试,设置如下(为简洁起见省略了一些内容):

持久性

public struct PatientData
{
    public int? ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public interface IPatientRepository : IDisposable
{
    IEnumerable<PatientData> GetPatients();
    PatientData GetPatientByID(int patientID);
    void InsertPatient(PatientData patient);
    void DeletePatient(int patientID);
    void UpdatePatient(PatientData patient);
    void Save();
}


class PatientRepositoryEF : IPatientRepository, IDisposable
{
  // assume EF implementation here
}

public static class Factory
{
    public static IPatientRepository GetPatientRepository() {
        // not ideal, will refactor later
        // assume EF for now
        return new PatientRepositoryEF();
    }
}

核心

public class Patient
{

    // CTORS/DTORS
    public Patient() {
        this.repository = Persistence.Core.Factory.GetPatientRepository();
    }

    public Patient(Persistence.Core.IPatientRepository repository) {
        // for testability, haven't actually used...
        this.repository = repository;
    }

    ~Patient() {
        if (repository != null) {
            repository.Dispose();
        }
    }

    // PERSISTENCE
    private Persistence.Core.IPatientRepository repository;

    public void Fill(int patientID) {
        Persistence.Core.PatientData data = repository.GetPatientByID(patientID);
        this.ID = data.ID;
        this.FirstName = data.FirstName;
        this.LastName = data.LastName;
    }

    public void Save() {
        repository.Save();
    }

    // other domain stuff

}

测试

    static void Main(string[] args) {

        Patient p = new Patient();

        p.Fill(1546);

        // test that data fills ok
    }

这一切都很好,但我想转储公共 Fill 方法并设置一个公共构造函数来获取一个 ID,以便消费者可以 a)创建一个新的/空的 Patient,或者 b)通过 ctor 传递一个 ID 到相应地填充模型。 想象一下这些变化:

将新的 CTor 添加到 Core.Patient 并私有化 fill():

    public Patient(int patientID) {
        this.repository = Persistence.Core.Factory.GetPatientRepository();
        fill(patientID);
    }

    void fill(int patientID) { /* fill method here */ }

把测试项目改成这样:

    static void Main(string[] args) {

        Patient p = new Patient(1546);

        // test that data fills ok
    }

现在,在测试项目之前完美运行的地方(p.Fill 暴露),如果没有对 Persistence 项目的引用,我无法再编译测试项目(您必须添加对程序集“Persistence”的引用)

这不是一个主要问题,我可以解决它,但我认为埋葬那个 Fill() 方法会很好。我猜这与构造对象时的依赖可见性有关,但另一方面,它可以很好地运行测试项目中的无参数构造函数,而测试项目不需要持久性引用。

我不清楚为什么需要此参考,唯一的变化是参数与无参数构造。有人可以解释吗?

编辑:确切的错误是:

“Persistence.Core.IPatientRepository”类型在未引用的程序集中定义。您必须添加对程序集“Persistence, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”的引用。

如果我用Patient p = new Patient() 替换Patient p = new Patient(1546);,一切都很好。

谢谢

【问题讨论】:

  • fill(int patientID) public void fill(int patientID) 或无效fill(int patientID)
  • 是public的,我改成private从构造函数中调用,此时无法编译外层测试项目。
  • 这只是对代码的评论,但我不得不将您指向Why are mutable structs "evil"? 以潜在地避免未来的头痛。
  • 感谢 31eee384,我还没有完全决定在那里使用结构 - 我过去曾将它们用于 MVVM PropertyChanged 支持,它运行良好,但我没有看到这个讨论。也就是说,我以前被它们咬过,从那以后就变得小心了:)
  • 至少对我而言,有几个“代码味道”:1) 患者有对其 PatientRepository 的引用。听起来很糟糕。 2)终结器中的代码,处理存储库引用。终结器将运行...当 GC 决定调用它时,(或者永远不会,如果您在该对象上调用 GC.SuppressFinalize)。即,您不知道它何时运行。听起来也很糟糕。 _repository.Dispose() 有什么作用?如果它“重要”,你应该控制它何时发生,如果不是......为什么在终结器中调用它?

标签: c# constructor repository-pattern


【解决方案1】:

编辑:

this.repository = Persistence.Core.Factory.GetPatientRepository(); 行似乎导致了您的错误。您意识到命名空间Persistence.Core 与您的项目Core 不同,对吧?听起来你有一个命名空间和/或参考问题,你只需要系统地跟踪它。很难远程解决这个问题。


所有项目依赖项必须链接一次且不超过一次(否则会出现可怕的循环依赖项编译错误)。因此,在您的情况下,Core 项目必须有对Persistence 的正式引用,然后Test 必须有对Core 的正式引用(但不是Persistence)。如果Persistence 必须在Core 之外直接使用,那么您需要通过Core 公开它或考虑重构您的设计。

对于那些试图创建典型的 3 层架构而没有做全部工作以真正隔离第 1 层和第 3 层的人来说,循环依赖问题可能会令人沮丧。两种可能有帮助的技术是事件处理程序/回调方法和使用更多接口进行重构.这两种技术都容易需要大量重构,这很快就会促使人们在开始按键之前在设计阶段进行长时间的思考。

采用 2 层架构并不总是很糟糕(取决于具体的环境),但如果您确实走这条路,强烈建议您合并业务逻辑和数据层。与存储层相比,表示层几乎总是会经历更频繁和激进的变化,因此选择该层作为隔离层是有意义的。

【讨论】:

  • 这正是我的设置:测试 -> 核心 -> 持久性。测试引用 only 核心,而不是持久性(在问题中,请注意错误消息指出它给出了编译错误,因为存在 no 对持久性的引用,而不是因为存在 )。除此之外,您所说的情况无论如何都不会是循环依赖。测试没有直接引用持久性,因此我很困惑。
  • 谢谢,但是不,这不能重构为更少的层。我的问题是,如果我使用公共 ctor 从 Core 中加载存储库,为什么它告诉我需要从 Test 到 Persistence 的引用,但如果我使用私有方法而不是。
  • 听起来您的 Visual Studio 出现故障,因为某些项目程序集不同步。尝试执行“清洁解决方案”,然后执行“重建解决方案”。如果这不起作用,请尝试删除所有项目引用,进行清理,然后重新引用所有项目,然后重新构建。
  • 不走运,如果我在测试项目中包含Patient p = new Patient(12345);,仍然不允许我构建解决方案。除了无参数的构造函数之外什么都不喜欢。
  • 您能否编辑您的问题以提供您得到的确切错误(逐字)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 2021-11-24
  • 2015-04-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多