You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用对象初始化器嵌套声明时,如何从子对象引用匿名父对象?

能否用嵌套对象初始化器实现孙类引用父类实例?

很遗憾,没办法直接通过嵌套对象初始化器实现你想要的写法。核心原因在于C#对象初始化器的执行逻辑:当你调用new InvoiceLineBreakdown(...)时,外层的InvoiceLineModel实例虽然已经被创建(构造函数已执行),但它是一个匿名对象——在当前的嵌套上下文中,你没有任何变量可以引用到它,自然没法传入孙类的构造函数。

可行的替代方案

既然直接嵌套初始化走不通,有几种变通的方法可以实现需求:

1. 显式声明中间对象(最推荐)

这是最清晰、最易维护的方式,把中间的InvoiceLineModel赋值给变量,之后在创建孙类时直接引用这个变量:

public InvoiceHeaderModel BuildAnInvoice() {
    // 先创建并保存父类实例
    var invoiceLine = new InvoiceLineModel();
    
    // 给父类添加孙类,传入已保存的父实例
    invoiceLine.InvoiceLineBreakdowns = new List<InvoiceLineBreakdown> {
        new InvoiceLineBreakdown(invoiceLine),
        new InvoiceLineBreakdown(invoiceLine) // 注意:你的类没有无参构造,这里必须传父实例
    };
    
    // 组装最终的头部对象
    return new InvoiceHeaderModel {
        InvoiceLineModels = new List<InvoiceLineModel> { invoiceLine }
    };
}

2. 延后设置父引用(需修改孙类)

如果可以修改InvoiceLineBreakdown的结构,你可以添加无参构造函数和可写的父引用属性,之后在初始化完成后统一设置父关系:

// 修改孙类,添加无参构造和可写属性
public class InvoiceLineBreakdown { 
    public InvoiceLineBreakdown() {} // 新增无参构造
    public InvoiceLineBreakdown(InvoiceLineModel parentInvoiceLine) { 
        _parentInvoiceLine = parentInvoiceLine; 
    } 
    private InvoiceLineModel _parentInvoiceLine; 
    public InvoiceLineModel ParentInvoiceLine { 
        get => _parentInvoiceLine; 
        set => _parentInvoiceLine = value; 
    }
}

// 初始化后遍历设置父引用
public InvoiceHeaderModel BuildAnInvoice() {
    var invoiceHeader = new InvoiceHeaderModel {
        InvoiceLineModels = new List<InvoiceLineModel> {
            new InvoiceLineModel {
                InvoiceLineBreakdowns = new List<InvoiceLineBreakdown> {
                    new InvoiceLineBreakdown(),
                    new InvoiceLineBreakdown()
                }
            }
        }
    };
    
    // 遍历所有层级,设置父引用
    foreach (var line in invoiceHeader.InvoiceLineModels) {
        foreach (var breakdown in line.InvoiceLineBreakdowns) {
            breakdown.ParentInvoiceLine = line;
        }
    }
    
    return invoiceHeader;
}

不过这种方法会破坏封装性(父引用可以被外部随意修改),如果对数据完整性要求较高,不太推荐。

3. 结合LINQ的工厂式写法

如果你想尽量贴近嵌套的写法,可以用LINQ的Select来创建并初始化父类对象,这样在闭包中可以引用到当前的父实例:

public InvoiceHeaderModel BuildAnInvoice() {
    return new InvoiceHeaderModel {
        InvoiceLineModels = new List<InvoiceLineModel> { new InvoiceLineModel() }
            .Select(line => {
                // 在闭包中可以直接引用当前的line实例
                line.InvoiceLineBreakdowns = new List<InvoiceLineBreakdown> {
                    new InvoiceLineBreakdown(line),
                    new InvoiceLineBreakdown(line)
                };
                return line;
            })
            .ToList()
    };
}

这种写法比显式变量稍紧凑,但可读性略低,适合简单场景。

总结

如果你坚持要使用嵌套对象初始化器的语法,没有办法直接实现孙类构造函数引用外层匿名父对象的需求——这是C#语言本身的限制。最稳妥的方式还是显式声明中间变量,这种写法不仅清晰,也方便后续的调试和维护。

内容的提问来源于stack exchange,提问作者tomRedox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:33:25