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

C#跨项目扩展类属性:在引用项目中扩展源类的实现方法

跨项目扩展类属性的几种实现方案

针对你在项目2中扩展项目1类属性的需求,以下是几种实用的实现方案,覆盖不同场景:

1. 继承(最直观的方案)

如果项目1中的类不是密封类(sealed),可以直接在项目2中继承这些类并添加新属性。需要注意的是,若原数据是项目1类的实例,需转换为子类实例才能使用扩展属性。

示例代码

项目1(ProjectA):

public class ClassB 
{
    public int Id { get; set; }
    public string SomeField { get; set; }
}

public class ClassC
{
    public string Code { get; set; }
    public DateTime CreateTime { get; set; }
}

项目2(ProjectB):

// 扩展ClassB
public class ClassBExtended : ProjectA.ClassB
{
    public string Name { get; set; }
    public string Phone { get; set; }
}

// 扩展ClassC
public class ClassCExtended : ProjectA.ClassC
{
    public string Remark { get; set; }
    public bool IsValid { get; set; }
}

使用方式

将原项目的实例转换为扩展类实例后,即可同时操作原字段和新属性:

// 假设原方法返回项目1的ClassB列表
List<ProjectA.ClassB> originalData = await SomeFunction();

// 转换为扩展类列表
List<ClassBExtended> extendedData = originalData.Select(b => new ClassBExtended
{
    Id = b.Id,
    SomeField = b.SomeField,
    Name = "默认名称",
    Phone = "123456"
}).ToList();

// 操作原字段与扩展属性
extendedData.ForEach(x =>
{
    x.Id = 1;
    x.SomeField = "更新后的值";
    x.Name = "新名称";
});

2. 装饰器模式(灵活包装原实例)

如果项目1的类是密封类,或不想用继承,可以用装饰器模式:创建包装类持有原类实例,同时扩展新属性,直接访问原类的所有成员。

示例代码(项目2)

public class ClassBDecorator
{
    // 持有原类实例
    public ProjectA.ClassB Original { get; }
    // 扩展属性
    public string Name { get; set; }
    public string Phone { get; set; }

    public ClassBDecorator(ProjectA.ClassB original)
    {
        Original = original ?? throw new ArgumentNullException(nameof(original));
    }
}

public class ClassCDecorator
{
    public ProjectA.ClassC Original { get; }
    public string Remark { get; set; }
    public bool IsValid { get; set; }

    public ClassCDecorator(ProjectA.ClassC original)
    {
        Original = original ?? throw new ArgumentNullException(nameof(original));
    }
}

使用方式

List<ProjectA.ClassB> originalData = await SomeFunction();

// 包装原实例
List<ClassBDecorator> decoratedData = originalData.Select(b => new ClassBDecorator(b)
{
    Name = "默认名称",
    Phone = "123456"
}).ToList();

// 操作原字段与扩展属性
decoratedData.ForEach(x =>
{
    x.Original.Id = 1;
    x.Original.SomeField = "更新后的值";
    x.Name = "新名称";
});

3. 模拟扩展属性(无额外类实现)

C#没有原生扩展属性,但可以通过扩展方法+弱引用字典模拟,适合不想创建新类的场景,同时避免内存泄漏。

示例代码(项目2)

using System.Collections.Concurrent;
using System.WeakReference;

// 为ClassB模拟扩展属性
public static class ClassBExtensions
{
    // 用弱引用字典存储扩展属性,避免内存泄漏
    private static readonly ConcurrentDictionary<WeakReference<ProjectA.ClassB>, (string Name, string Phone)> _extendedProps = new();

    public static string GetName(this ProjectA.ClassB obj)
    {
        if (_extendedProps.TryGetValue(GetWeakRef(obj), out var props))
            return props.Name;
        return null;
    }

    public static void SetName(this ProjectA.ClassB obj, string value)
    {
        var weakRef = GetWeakRef(obj);
        if (_extendedProps.TryGetValue(weakRef, out var props))
            _extendedProps[weakRef] = (value, props.Phone);
        else
            _extendedProps[weakRef] = (value, null);
    }

    public static string GetPhone(this ProjectA.ClassB obj)
    {
        if (_extendedProps.TryGetValue(GetWeakRef(obj), out var props))
            return props.Phone;
        return null;
    }

    public static void SetPhone(this ProjectA.ClassB obj, string value)
    {
        var weakRef = GetWeakRef(obj);
        if (_extendedProps.TryGetValue(weakRef, out var props))
            _extendedProps[weakRef] = (props.Name, value);
        else
            _extendedProps[weakRef] = (null, value);
    }

    private static WeakReference<ProjectA.ClassB> GetWeakRef(ProjectA.ClassB obj)
    {
        // 查找已存在的弱引用,避免重复创建
        foreach (var kvp in _extendedProps.Keys)
        {
            if (kvp.TryGetTarget(out var target) && target == obj)
                return kvp;
        }
        return new WeakReference<ProjectA.ClassB>(obj);
    }
}

使用方式

List<ProjectA.ClassB> data = await SomeFunction();
data.ForEach(x =>
{
    // 操作原字段
    x.Id = 1;
    x.SomeField = "测试值";
    // 设置/获取扩展属性
    x.SetName("张三");
    x.SetPhone("138xxxxxxx");
    var userName = x.GetName();
});

4. 匿名类型/ValueTuple(临时场景快速实现)

如果只是临时需要携带额外属性,不需要长期维护,可以用匿名类型或ValueTuple包装原对象:

List<ProjectA.ClassB> originalData = await SomeFunction();

// 使用ValueTuple(可修改属性)
var extendedData = originalData.Select(b => (Original: b, Name: "默认名称", Phone: "123456")).ToList();

extendedData.ForEach(x =>
{
    x.Original.Id = 1;
    x.Original.SomeField = "更新后的值";
    x.Name = "新名称"; // ValueTuple的属性可修改
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:35:59