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

如何在C#中实现带特性的属性复用(替代多继承)

可行的实现方案

方案1:单基类整合(最简单直接)

把需要复用的Name、Address属性合并到一个基类里,所有需要这些属性的类直接继承这个基类,特性只需要写一次:

public class BaseCommon
{
    [StringLength(100), MaxLength(100)]
    public string Name { get; set; }

    [StringLength(100), MaxLength(100)]
    public string Address { get; set; }
}

public class ClassA : BaseCommon
{
    public string City { get; set; }
}

public class ClassB : BaseCommon
{
    public string Country { get; set; }
}

如果原本想把Name和Address拆分到不同逻辑组,这个方案可能不够灵活,但胜在简单,完全符合C#的继承规则,特性也只维护一次。

方案2:组合模式(保持属性分组)

如果必须把Name和Address拆分到不同的逻辑类里,用组合代替继承:先定义包含属性和特性的独立类,再在业务类里持有这些类的实例,通过转发属性暴露出去,特性只在独立类里写一次:

public class NameHolder
{
    [StringLength(100), MaxLength(100)]
    public string Name { get; set; }
}

public class AddressHolder
{
    [StringLength(100), MaxLength(100)]
    public string Address { get; set; }
}

public class ClassA
{
    private readonly NameHolder _nameHolder = new NameHolder();
    private readonly AddressHolder _addressHolder = new AddressHolder();

    // 转发Name属性,复用NameHolder里的特性
    public string Name
    {
        get => _nameHolder.Name;
        set => _nameHolder.Name = value;
    }

    // 转发Address属性,复用AddressHolder里的特性
    public string Address
    {
        get => _addressHolder.Address;
        set => _addressHolder.Address = value;
    }

    public string City { get; set; }
}

注意:如果你的业务需要通过反射读取ClassA的Name属性上的特性,需要额外处理(比如反射时读取_nameHolder的对应属性),但如果是常规的属性使用或数据验证,这个方案完全可行。

方案3:代码生成器(适合大量类的场景)

如果需要复用的属性组合多、业务类数量大,用代码生成器自动生成重复代码。比如用C#的Source Generator或者T4模板,只需要编写一次属性和特性的模板,就能自动给所有业务类生成对应的属性代码,完全避免手动重复编写。

比如用Source Generator的思路:定义一个标记特性,给需要生成属性的类打上标记,然后生成器自动添加Name、Address属性及对应的特性。

方案4:默认接口方法(C# 8.0+,需注意特性兼容性)

把属性定义在接口里并添加默认实现,然后让业务类实现这些接口。不过接口属性上的特性在反射时需要单独读取,部分数据验证框架可能需要配置支持接口特性,所以这个方案要结合业务场景使用:

public interface IHasName
{
    [StringLength(100), MaxLength(100)]
    string Name { get; set; }
}

public interface IHasAddress
{
    [StringLength(100), MaxLength(100)]
    string Address { get; set; }
}

// 可选:用一个基类统一实现接口,避免每个业务类重复写实现
public class BaseWithCommonProps : IHasName, IHasAddress
{
    public string Name { get; set; }
    public string Address { get; set; }
}

public class ClassA : BaseWithCommonProps
{
    public string City { get; set; }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:55:26