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

C#类属性Getter和Setter写法是否正确?求规范写法指导

你的C#属性与Cloneable实现分析与修正

咱们一步步拆解你的代码问题,先从属性写法说起,再聊Cloneable接口的实现优化:

一、属性写法的合理性问题

首先看你的Name属性,这里存在逻辑不一致的明显问题:

  • get方法完全没用到私有变量_name,而是返回Id + "/" + Code的计算值
  • set方法却把值存到_name里,但这个值永远不会被读取到

这会导致怪异的行为:当你给Name赋值后,读取Name时得到的依然是Id/Code,完全忽略了你设置的内容。得根据你的实际需求调整,有两种修正方向:

1. 如果Name是计算属性(仅由Id和Code推导)

那它应该是只读的,不需要set方法和私有变量_name,写法可以简化:

public string Name 
{
    get { return Id == null ? null : $"{Id}/{Code}"; }
}

2. 如果Name需要独立存储值

那get方法应该返回存储的_name,而不是计算值,同时保留你的判重逻辑:

private string _name;
public string Name 
{
    get { return _name; }
    set { if (_name != value) _name = value; }
}

如果同时需要基于Id和Code的派生值,可以新增一个单独的只读属性,比如DerivedName。

另外,IsValid属性可以简化成更简洁的表达式写法:

public bool IsValid => Id != null;

二、Cloneable接口的实现优化

你的Clone实现思路是可行的,但有几个可以优化的点:

1. 强类型返回更友好

ICloneable的Clone方法默认返回object,你可以通过显式实现接口+强类型方法的方式,让调用更方便:

// 显式实现ICloneable接口
object ICloneable.Clone() => Clone();

// 强类型的Clone方法,外部调用更直观
public Element Clone() 
{
    var elem = new Element();
    SetPropertyValues(elem);
    return elem;
}

2. 反射逻辑的优化

  • 你在Where里已经过滤了CanWrite的属性,所以foreach里的if (property.CanWrite)判断是多余的,可以直接去掉
  • 如果类的属性不会频繁变动,建议缓存反射得到的PropertyInfo集合,避免每次Clone都重新反射,提升性能:
    private static readonly PropertyInfo[] _writableProperties = 
        typeof(Element).GetProperties()
            .Where(p => p.CanWrite && (p.PropertyType.IsValueType || p.PropertyType.IsEnum || p.PropertyType == typeof(string)))
            .ToArray();
    
    private void SetPropertyValues(Element elem) 
    {
        foreach (var property in _writableProperties) 
        {
            property.SetValue(elem, property.GetValue(this));
        }
    }
    

3. 浅拷贝vs深拷贝

当前的实现是浅拷贝,对于值类型、字符串(不可变引用类型)来说没问题,但如果后续添加了自定义引用类型属性,需要考虑是否要实现深拷贝——这时候反射的方式就不够了,得手动处理那些引用类型的Clone逻辑。

4. 替代方案:手动复制属性

如果类的属性数量不多,手动复制比反射更高效、更直观,比如:

public Element Clone() 
{
    return new Element
    {
        Id = this.Id,
        Code = this.Code,
        // 注意:如果Name是计算属性,不需要复制,新对象会自己计算
        // 如果Name是存储属性,这里复制this.Name即可
    };
}

这种方式没有反射的性能开销,也更易维护。

修正后的完整代码示例

假设你选择把Name设为计算属性,最终代码可以是这样:

public class Element : ICloneable
{
    public int? Id { get; set; }
    public string Code { get; set; }

    // 计算属性,只读
    public string Name => Id == null ? null : $"{Id}/{Code}";

    public bool IsValid => Id != null;

    // 显式实现ICloneable
    object ICloneable.Clone() => Clone();

    // 强类型Clone方法
    public Element Clone() 
    {
        var elem = new Element();
        SetPropertyValues(elem);
        return elem;
    }

    private static readonly PropertyInfo[] _writableProperties = 
        typeof(Element).GetProperties()
            .Where(p => p.CanWrite && (p.PropertyType.IsValueType || p.PropertyType.IsEnum || p.PropertyType == typeof(string)))
            .ToArray();

    private void SetPropertyValues(Element elem) 
    {
        foreach (var property in _writableProperties) 
        {
            property.SetValue(elem, property.GetValue(this));
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:34:57