C#中能否针对类的每个实例修改对应Attribute存储的关联数据?
解答
C# 中无法通过 Attribute 实现你要的「每个类实例独立存储数据」的需求。
Attribute 是属于类型的元数据,同一个类的所有实例共享同一个 Attribute 实例,你修改了其中一个实例对应 Attribute 里的字段,所有该类的实例读到的值都会同步变化,完全不符合你的使用场景。
你提到的 TypeScript 装饰器可以动态返回子类附加字段的效果,在 C# 中有几种替代实现方案:
方案1:使用 ConditionalWeakTable 存储实例附加数据(最贴近需求,原类无感知)
这个方案不需要修改你已定义的 Player 类代码,通过运行时附加的方式存储每个实例的独立状态,且不会影响实例的GC回收,不会产生内存泄漏:
using System.Runtime.CompilerServices; public static class GameObjectExtensions { // 存储每个实例对应的附加数据 private static readonly ConditionalWeakTable<object, GameObjectExtraData> _instanceExtraData = new(); // 自定义的附加数据结构,可按需扩展字段 private class GameObjectExtraData { public bool Initialized { get; set; } } // 扩展方法读取初始化状态 public static bool IsInitialized(this object gameObject) { return _instanceExtraData.TryGetValue(gameObject, out var data) && data.Initialized; } // 扩展方法设置初始化状态 public static void SetInitialized(this object gameObject, bool value) { var data = _instanceExtraData.GetOrCreateValue(gameObject); data.Initialized = value; } }
你原本的 Tick 逻辑可以直接改造为:
internal class Core { async void Tick() { while (isRunning) { foreach (var gameObject in gameObjects) { if (!gameObject.IsInitialized()) { // 执行初始化逻辑 gameObject.SetInitialized(true); } } await Task.Delay(1); } } }
方案2:公共基类继承(改造成本最低)
如果允许修改业务类的定义,可以直接抽象一个公共基类存放通用字段,逻辑最简单直观:
public abstract class GameObjectBase { public bool Initialized { get; set; } } [GameObject] public class Player : GameObjectBase { // 原有逻辑无需改动 }
使用时直接强转后访问字段即可:
if (gameObject is GameObjectBase obj && !obj.Initialized) { // 初始化逻辑 obj.Initialized = true; }
方案3:动态代理生成子类(完全复刻TS装饰器逻辑)
如果需要和TS装饰器完全一致的「标记Attribute后自动生成附加字段的子类」效果,可以引入Castle DynamicProxy等动态代理库,在实例化对象时自动生成继承自原类的代理子类,附加对应的字段。该方案复杂度较高,需要调整实例化逻辑,一般场景下不需要用到。
内容的提问来源于stack exchange,提问作者Get Off My Lawn
相关产品推荐
相关产品推荐

