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

如何安全返回列表项以供编辑?C# Builder类实现疑问

问题

我创建了一个ElementBuilder类,用来便捷创建由统一接口IElement的不同类型对象组成的列表。调用类方法创建列表项时,方法会返回列表中新创建的对象供编辑。目前代码能正常运行,但我不确定直接返回列表项来修改属性是否安全?如果不安全,该怎么安全返回列表元素来进行编辑?

示例代码

var builder = new ElementBuilder();
var item = builder.AddText("abc");

// 编辑新引用元素的属性,修改应同步到builder中的对象
item.Bold = true;

.....

// 将包含已添加项的builder实例传递到其他地方

// 对上述添加的元素执行如下操作
var x = builder.First() as TextElement; 
Console.WriteLine(x.Text);
Console.WriteLine(x.Bold);

// 预期输出:
abc
true

ElementBuilder类实现

public class ElementBuilder
{

    private List<IElement> elements =  new List<IElement>();;

    public TextElement AddText (string text)
    {
        var item = new TextElement (text);
        elements.Add(item);
// 返回对象以供编辑,修改应影响列表中的项
        return elements.First(x => x == item);
    }

    public ImageElement AddImage (string imageUrl)
    {
        var item = new ImageElement (imageUrl);
        elements.Add(item);

// 返回对象以供编辑,修改应影响列表中的项
        return elements.First(x => x == item);
    }

    public IElement First() 
    {
        return elements.First();
    }

    .....
}

分析与解决方案

直接返回对象的安全性

直接返回列表中对象的引用是安全的,因为你返回的就是列表里实际存储的对象实例引用——对返回的引用修改属性,自然会同步到列表中的对象,完全符合你的预期。

不过你当前代码里有个多余操作:return elements.First(x => x == item);,既然已经创建了item并添加到列表,直接返回item就行,没必要再去列表里遍历查找,既浪费性能又没必要。

若要更严格的安全控制:可选方案

如果担心外部拿到引用后随意修改敏感属性、或者破坏内部状态,可以考虑以下两种方式:

1. 不可变对象 + 链式修改

把TextElement、ImageElement设计成不可变类,属性仅在构造时初始化,修改属性时返回新实例,同时在ElementBuilder中提供更新方法替换列表内的对象:

// 不可变TextElement示例
public class TextElement : IElement
{
    public string Text { get; }
    public bool Bold { get; }

    public TextElement(string text, bool bold = false)
    {
        Text = text;
        Bold = bold;
    }

    // 返回新实例,不修改原对象
    public TextElement WithBold(bool bold)
    {
        return new TextElement(Text, bold);
    }
}

// 改造后的ElementBuilder
public class ElementBuilder
{
    private List<IElement> elements = new List<IElement>();

    public TextElement AddText(string text)
    {
        var item = new TextElement(text);
        elements.Add(item);
        return item;
    }

    // 提供更新方法,替换列表中的旧实例
    public void UpdateElement(IElement oldElement, IElement newElement)
    {
        var index = elements.IndexOf(oldElement);
        if (index != -1)
        {
            elements[index] = newElement;
        }
    }
}

// 使用方式
var builder = new ElementBuilder();
var item = builder.AddText("abc");
var updatedItem = item.WithBold(true);
builder.UpdateElement(item, updatedItem);

这种方式彻底避免了外部直接修改内部对象的风险,但需要调整元素类的设计逻辑。

2. 返回包装类,限制可修改属性

创建一个代理包装类,只暴露允许外部修改的属性,内部持有真实元素的引用,修改操作同步到真实对象:

public class TextElementProxy
{
    private readonly TextElement _realElement;

    public TextElementProxy(TextElement realElement)
    {
        _realElement = realElement;
    }

    // 仅暴露允许修改的属性
    public bool Bold
    {
        get => _realElement.Bold;
        set => _realElement.Bold = value;
    }

    // 敏感/只读属性仅提供getter
    public string Text => _realElement.Text;
}

// 修改ElementBuilder的AddText方法
public class ElementBuilder
{
    private List<IElement> elements = new List<IElement>();

    public TextElementProxy AddText(string text)
    {
        var item = new TextElement(text);
        elements.Add(item);
        return new TextElementProxy(item);
    }
}

这种方式可以精确控制外部能修改的属性范围,避免不必要的暴露,但需要额外编写包装类。

总结

  • 如果只是需要外部修改元素的公开属性,当前直接返回对象引用的方式安全且高效,建议把return elements.First(x => x == item);改成直接return item;。
  • 如果需要严格控制外部对元素的修改权限,可选择不可变对象+更新方法,或者包装类的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:30:46