如何为嵌套对象创建生成器

How to created builder for nested objects

我正在寻找一种方法来创建可以创建嵌套对象的构建器。

我已经读过这个主题: 但这种方法是 modyfing model/entities,我想避免。

我有几个型号: 广告有一个所有者所有者有一个地址地址 有一个 联系人 实体。

public class Advertisment
{
    public string AdvertismentId { get; set; }
    public Owner Owner { get; set; }
}
public class Owner
{
    public string Name { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string Street { get; set; }
    public Contact Contact { get; set; }
}
public class Contact
{
    public string PhoneNo { get; set; }
}

我想链接这样的方法(或类似的方法):

        var ad = new AdBuilder()
                    .WithId("123")
                    .WithOwner(x =>
                        x.WithName("NameOfOwner")
                        x.WithAddress(x => x.WithStreet("SomeStreet"))
                        .WithContact(y => y.WithPhoneNo("123-345-789"))));

我在这里准备了代码: https://rextester.com/TRN19779

我不想修改模型,因为它们是从 JSON 架构生成的,我将它们保存在单独的 class 库中。我将使用上面的构建器将一个对象映射到另一个对象。 我正在准备一个对象发送给第 3 方消费者。

有人会这么友善并提供一点帮助吗?

这可以使用接口来完成。每个子 object 都有一个 interface 用于构造它。例如,Owner class 具有相应的 IOwner 接口,允许用户填充 Owner class.

的属性
public interface IBuild
{
    Advertisement Build( );
}

public interface IAdvertisement : IBuild
{
    IAdvertisement WithID( string id );
    IAdvertisement WithOwner( Action<IOwner> func );
}

public interface IOwner
{
    IOwner WithName( string name );
    IOwner WithAddress( Action<IAddress> func );
}

public interface IAddress
{
    IAddress WithStreet( string street );
    IAddress WithContact( Action<IContact> func );
}

public interface IContact
{
    IContact WithPhoneNumber( string phoneNumber );
}

public class AdvertisementBuilder : IAdvertisement, IOwner, IAddress, IContact
{
    private readonly Advertisement _advert = new( )
    { Owner = new( ) { Address = new( ) { Contact = new( ) } } };

    private AdvertisementBuilder( )
    { }

    public static IAdvertisement Create( ) => 
        new AdvertisementBuilder( );        

    public IOwner WithAddress( Action<IAddress> func )
    {
        func( this );
        return this;
    }

    public IAddress WithContact( Action<IContact> func )
    {
        func( this );
        return this;
    }

    public IAdvertisement WithID( string id )
    {
        _advert.AdvertisementId = id;
        return this;
    }

    public IOwner WithName( string name )
    {
        _advert.Owner.Name = name;
        return this;
    }

    public IAdvertisement WithOwner( Action<IOwner> func )
    {
        func( this );
        return this;
    }

    public IContact WithPhoneNumber( string phoneNumber )
    {
        _advert.Owner.Address.Contact.PhoneNo = phoneNumber;
        return this;
    }

    public IAddress WithStreet( string street )
    {
        _advert.Owner.Address.Street = street;
        return this;
    }

    // Here you can do some validation and make sure 
    // any required information has been filled in.
    public Advertisement Build( ) => _advert;
}


static void Main( string[ ] _ )
{
    var advertisement = AdvertisementBuilder.Create( )
        .WithID( "Some id" )
        .WithOwner( o => o.WithName( "Bill" )
            .WithAddress( a => a.WithStreet( "Some street" )
            .WithContact( c => c.WithPhoneNumber( "905-334-5839" ) ) ) )
        .Build( );
}