具有循环依赖的不可变数据

immutable data with circular dependencies

我有一堆 classes 应该代表数据。这些 class 是嵌套的,因此它们形成了一棵树(或者,在简单的情况下,形成一条链)。由于数据应该只创建一次然后只读,我使用 classes 和 init-only 属性:

public class Foo { public Bar Bar { get; init; } }
public class Bar { public Baz Baz { get; init; } }
public class Baz { public int Value { get; init; } }

为了不只是从上到下导航这样的 tree/chain,我需要每个 [=37= 的 Owner(或 Parent)属性 ].所以让我们假设我是这样的:

public interface IData { }

public class Data<OwnerType> : IData where OwnerType : IData
{ public OwnerType Owner { get; init; } }

public class Foo : IData { public Bar Bar { get; init; } }
public class Bar : Data<Foo> { public Baz Baz { get; init; } }
public class Baz : Data<Bar> { public int Value { get; init; } }

但是现在我遇到了循环依赖的问题:为了创建一个非空的Foo,我必须在构建过程中设置它的Foo.Bar 属性。但是那个 Bar 对象需要一个 Foo 对象作为 Bar.Owner 属性 在构造期间设置,它不能是当前正在创建的 Foo (因为它还没有尚未创建),尽管它应该是这样的。

var foo = new Foo { Bar = new Bar { Owner = foo, ... } }; // this does not work but this is what I want

如何解决这个问题?

我可以让 Owner 属性 有一个(私有的)setter。但我不喜欢这个因为 private 没有说 this can be set only once.

"A" 解决方案是将 Data 的 setter 设为 public,并将其设置在 class构造函数。

注意:恕我直言 Data 是一个不好的名字,所以我将其重命名为:

public interface IsOwner { }

public class OwnedBy<OwnerType> where OwnerType : IsOwner
{ public OwnerType Owner { get; set; } }

public class Foo : IsOwner
{
    public Bar _bar { get; init; }
    public Foo(Bar bar)
    {
        bar.Owner = this;
        _bar = bar;
    }
}
public class Bar : OwnedBy<Foo>, IsOwner
{ 
    public Baz _baz { get; init; }

    public Bar(Baz baz)
    {
        baz.Owner = this;
        _baz = baz;
    }
}
public class Baz : OwnedBy<Bar>
{
    public int _value { get; init; }

    public Baz(int value)
    {
        _value = value;
    }
}

static class Program
{
    static void Main()
    {
        var foo = new Foo(new Bar(new Baz(1)));
    }
}

编辑:我错过了您问题中的 set-once 项。 您确实可以使用私有字段支持 Owner,确保它被设置一次

public class OwnedBy<OwnerType> where OwnerType : IsOwner
{
    private OwnerType owner;

    public OwnerType Owner { get => owner; set => owner ??= value; }
}

甚至设置两次抛出异常

public OwnerType Owner
{
    get => owner; set {
        if (owner is not null) throw new InvalidOperationException(
           $"{nameof(Owner)} can only be set once");
        owner = value;
    }
}