PostSharp:删除/替换后备字段

时间:2015-08-14 17:40:04

标签: c# postsharp

我试图通过删除/替换支持字段来查找PostSharp是否可以轻松地用于更改类的结构。

以下是样本:

我们说,我有一个跟随实体

class DataItem
{
  public Int32 Id { get; set; }
  public String Name { get; set; }
  public Decimal? HourlyRateMon { get; set; }
  public Decimal? HourlyRateTue { get; set; }
  public Decimal? HourlyRateWed { get; set; }
  public Decimal? HourlyRateThu { get; set; }
  public Decimal? HourlyRateFri { get; set; }
}

将在每个实例的64位= 128字节上使用4 + 8 + 5 * 20 + 16字节开销。

我想要做的是应用一个方面,通过打包可以为空的小数来最小化对象的内存占用 - 比如

internal class DataItem
{
  private CompactDecimal _hourlyRateFri;
  private CompactDecimal _hourlyRateMon;
  private CompactDecimal _hourlyRateThu;
  private CompactDecimal _hourlyRateTue;
  private CompactDecimal _hourlyRateWed;

  public int Id { get; set; }
  public string Name { get; set; }

  public decimal? HourlyRateMon
  {
    get { return _hourlyRateMon; }
    set { _hourlyRateMon = value; }
  }

  public decimal? HourlyRateTue
  {
    get { return _hourlyRateTue; }
    set { _hourlyRateTue = value; }
  }

  public decimal? HourlyRateWed
  {
    get { return _hourlyRateWed; }
    set { _hourlyRateWed = value; }
  }

  public decimal? HourlyRateThu
  {
    get { return _hourlyRateThu; }
    set { _hourlyRateThu = value; }
  }

  public decimal? HourlyRateFri

  {
    get { return _hourlyRateFri; }
    set { _hourlyRateFri = value; }
  }
}

internal struct CompactDecimal
{
  public uint Offset;

  public static implicit operator decimal?(CompactDecimal d)
  {
    // here I can, for instance, go to a shared stream at the stream offset and read the decimal
  }

  public static implicit operator CompactDecimal(decimal? d)
  {
    // here I can, for instance, serialize the decimal to a shared stream and get the stream offset
  }
}

将在每个实例的64位= 48字节上使用4 + 8 + 5 * 4 + 16字节开销,节省80字节/实例。如果我们需要存储数百万个实例,它可以为我们节省大量内存。

我尝试创建一个LocationInterceptionAspect派生属性,但是我没有得到预期的结果 - 不仅原始的支持字段仍然存在,而且我还有10个TestAttribute实例(5个属性,每个获取/设置) :

// Fields
[NonSerialized]
private TestAttribute <>z__aspect10;
[NonSerialized]
private TestAttribute <>z__aspect11;
[NonSerialized]
private TestAttribute <>z__aspect12;
[NonSerialized]
private TestAttribute <>z__aspect13;
[NonSerialized]
private TestAttribute <>z__aspect4;
[NonSerialized]
private TestAttribute <>z__aspect5;
[NonSerialized]
private TestAttribute <>z__aspect6;
[NonSerialized]
private TestAttribute <>z__aspect7;
[NonSerialized]
private TestAttribute <>z__aspect8;
[NonSerialized]
private TestAttribute <>z__aspect9;
private decimal? <HourlyRateFri>k__OriginalField;
private decimal? <HourlyRateMon>k__OriginalField;
private decimal? <HourlyRateThu>k__OriginalField;
private decimal? <HourlyRateTue>k__OriginalField;
private decimal? <HourlyRateWed>k__OriginalField;

要么我做错了,要么PostSharp不支持我想要实现的目标。

TestAttribute现在什么都不做 -

[Serializable]
public class TestAttribute : LocationInterceptionAspect, IInstanceScopedAspect
{
  public override void CompileTimeInitialize(LocationInfo targetLocation, AspectInfo aspectInfo)
  {
    //base.CompileTimeInitialize(targetLocation, aspectInfo);
  }

  #region <<< Public methods >>>
  public Object CreateInstance(AdviceArgs adviceArgs)
  {
    return MemberwiseClone();
  }

  public override void OnGetValue(LocationInterceptionArgs args)
  {
    //args.
    //base.OnGetValue(args);
  }

  public override void OnSetValue(LocationInterceptionArgs args)
  {
    //base.OnSetValue(args);
  }

  public void RuntimeInitializeInstance()
  {
  }
  #endregion
}

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

首先,您还需要计算流本身使用的内存。基本上你只需用uint索引替换Nullable中的bool,从而不用任何东西。另外请注意,在64位机器上,内存填充为8个字节,因此decimal?大24个字节。

保存内存的方法是将可空类型的bool打包到位图中。但是,您需要引入一个字段并更改支持字段的类型。 PostSharp Aspect Framework不支持此功能。

其他方法是不使属性自动化,并使用可以使用引入的接口获取或设置值的方面覆盖getter和setter。但是在这种情况下,每个实例需要再增加2个对象 - 具有位图的实例级方面对象和用于保存值的十进制数组。这将产生这样的开销,即只有在类中使用8个可空值后才能保存内存。

稍微改进的是拥有一个具有数组和位图的公共基类。您将不再需要实例级方面,只需将十进制数组和位图保存在基类字段中。此方法将从5个可空值中保存内存。