UnityInjection icon indicating copy to clipboard operation
UnityInjection copied to clipboard

可以注入并使用一些字段吗?

Open xzaxzaazx opened this issue 1 year ago • 5 comments

在注入方法的时候需要一些额外字段的支持,该怎么操作?

xzaxzaazx avatar May 29 '24 03:05 xzaxzaazx

我不太确定你想要额外字段是哪种形式。

如果是元数据意义上的额外成员,那么很遗憾,无法实现,这是任何注入库都在避免实现的功能。btw,这个需求在某些情况下可以使用源生成解决。

如果你只是想通过增加几个变量来影响方法的行为,那么可以使用闭包来实现;如果你希望变量的生命周期关系与一个实际绑定,那么可以通过一个全局字典来实现(小心内存泄漏,同时应避免在unity中使用ConditionalWeakTable)

labbbirder avatar May 29 '24 05:05 labbbirder

我想实现类似Auto-Implemented Property的一些功能,我也想过全局字典,如果对static的字段还好说,但如果对每个instance都用字典处理是不是有点复杂?我看到InjectHelper里有注入field的步骤,是否可以做成一些工具开放?

xzaxzaazx avatar May 29 '24 07:05 xzaxzaazx

可否通过例子来说明

labbbirder avatar May 29 '24 12:05 labbbirder

例如一个属性

string name=>$"{lastName} {firstName}";

我希望它的getter在第一次调用后固化在一个field里,那样需要额外写一个string的field和一个bool去存储是否第一次调用,我觉得这样写一堆参数很影响代码的直观 于是我希望通过注入达到这样的效果:

[Const]string name=>$"{lastName} {firstName}";

将这个属性注成这样:

string name{get{
     if(!name_loaded_UID)name_data_UID=$"{lastName} {firstName}";
     return name_loaded_UID;
}}
bool name_loaded_UID;
string name_data_UID;

而这需要一个类似于现在InjectionInfo.Create的东西,也许长这样:

public static InjectionInfo CreateField(Type type, string fieldName, Action<FieldInfo> fieldReceiver);

xzaxzaazx avatar May 30 '24 01:05 xzaxzaazx

暴露LowLevel接口是可行的方法,这个后面会考虑。

对于这里的具体问题,事实上是cache功能。可以推广到任意有返回值的函数调用,字段取值操作是前者的子集。使用全局缓存表看起来是一个正确的选择,一个ConditionalWeakTable的临时平替可以实现为:

  • Key使用一个包含(MemberInfo,实参列表)的元组表示,Value是一个可空缓存值;
  • 对于键中的实参,如果是托管类型,需要用弱引用;
  • 数据结构上可以采用Bucket形式,访问子列表时,在可控范围内进行垃圾键删除;
  • 实参列表中任意一个弱引用为空时,则应视为垃圾键。

labbbirder avatar May 30 '24 08:05 labbbirder