PostSharp 的 LocationInterceptionAspect 不适用于结构
PostSharp's LocationInterceptionAspect doesn't work with structs
我做了一个 BitsAspect
来模拟 C++
位域,它是这样应用的:
[StructLayout(LayoutKind.Explicit)]
class Class {
[FieldOffset(0)] public byte Whole;
[FieldOffset(0)] [BitsAspect(0,0)] public byte Bit0;
[FieldOffset(0)] [BitsAspect(1,1)] public byte Bit1;
}
效果很好,但只适用于 class
es。在 struct
s 它根本不起作用:
[StructLayout(LayoutKind.Explicit)]
struct Struct {
[FieldOffset(0)] public byte Whole;
[FieldOffset(0)] [BitsAspect(0,0)] public byte Bit0;
[FieldOffset(0)] [BitsAspect(0,1)] public byte Bit1;
}
这是测试:
[TestMethod]
public void BitOperations_Test() {
var c = new Class();
c.Bit1 = 1;
Assert.AreEqual(2, c.Whole);
Assert.AreEqual(1, c.Bit1);
// all assertions pass to this point.
var s = new Struct();
s.Bit1 = 1;
Assert.AreEqual(2, s.Whole); // fails: s.Whole is 1 :-(
Assert.AreEqual(1, s.Bit1);
}
看点:
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Property | MulticastTargets.Field)]
public class BitsAspect : LocationInterceptionAspect {
private ulong _mask;
private Type _type;
public int BitOffset { get; private set; }
public int BitsCount { get; private set; }
public BitsAspect(int bitOffset, int bitsCount) {
BitOffset = bitOffset;
BitsCount = bitsCount;
}
public override void CompileTimeInitialize(LocationInfo targetLocation, AspectInfo aspectInfo) {
_type = targetLocation.LocationType;
if (_type.IsEnum) _type = _type.GetEnumUnderlyingType();
ulong mask = ((ulong) 1 << BitsCount) - 1;
_mask = mask << BitOffset;
base.CompileTimeInitialize(targetLocation, aspectInfo);
}
public override void OnGetValue(LocationInterceptionArgs args) {
var @this = args.Instance;
var oldValue = Convert.ToUInt64(args.Binding.GetValue(ref @this, Arguments.Empty));
var value = (oldValue & _mask) >> BitOffset;
var converted = Convert.ChangeType(value, _type);
args.Value = converted;
}
public override void OnSetValue(LocationInterceptionArgs args) {
var @this = args.Instance;
var newValue = Convert.ToUInt64(args.Value);
var oldValue = Convert.ToUInt64(args.Binding.GetValue(ref @this, Arguments.Empty));
var value = (oldValue & ~_mask) | (newValue << BitOffset);
var converted = Convert.ChangeType(value, _type);
args.SetNewValue(converted);
}
}
有什么方法可以用值类型 struct
s 实现这个吗?
结构上的 LocationInterceptionAspect 在这里应该可以正常工作。
Bit1 的声明对于 Class 有点不同:
[FieldOffset(0)] [BitsAspect(1,1)] public byte Bit1;
对于结构:
[FieldOffset(0)] [BitsAspect(0,1)] public byte Bit1;
我敢打赌这会有所作为。
注意可变值类型,它们可以是 pure evil.
我做了一个 BitsAspect
来模拟 C++
位域,它是这样应用的:
[StructLayout(LayoutKind.Explicit)]
class Class {
[FieldOffset(0)] public byte Whole;
[FieldOffset(0)] [BitsAspect(0,0)] public byte Bit0;
[FieldOffset(0)] [BitsAspect(1,1)] public byte Bit1;
}
效果很好,但只适用于 class
es。在 struct
s 它根本不起作用:
[StructLayout(LayoutKind.Explicit)]
struct Struct {
[FieldOffset(0)] public byte Whole;
[FieldOffset(0)] [BitsAspect(0,0)] public byte Bit0;
[FieldOffset(0)] [BitsAspect(0,1)] public byte Bit1;
}
这是测试:
[TestMethod]
public void BitOperations_Test() {
var c = new Class();
c.Bit1 = 1;
Assert.AreEqual(2, c.Whole);
Assert.AreEqual(1, c.Bit1);
// all assertions pass to this point.
var s = new Struct();
s.Bit1 = 1;
Assert.AreEqual(2, s.Whole); // fails: s.Whole is 1 :-(
Assert.AreEqual(1, s.Bit1);
}
看点:
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Property | MulticastTargets.Field)]
public class BitsAspect : LocationInterceptionAspect {
private ulong _mask;
private Type _type;
public int BitOffset { get; private set; }
public int BitsCount { get; private set; }
public BitsAspect(int bitOffset, int bitsCount) {
BitOffset = bitOffset;
BitsCount = bitsCount;
}
public override void CompileTimeInitialize(LocationInfo targetLocation, AspectInfo aspectInfo) {
_type = targetLocation.LocationType;
if (_type.IsEnum) _type = _type.GetEnumUnderlyingType();
ulong mask = ((ulong) 1 << BitsCount) - 1;
_mask = mask << BitOffset;
base.CompileTimeInitialize(targetLocation, aspectInfo);
}
public override void OnGetValue(LocationInterceptionArgs args) {
var @this = args.Instance;
var oldValue = Convert.ToUInt64(args.Binding.GetValue(ref @this, Arguments.Empty));
var value = (oldValue & _mask) >> BitOffset;
var converted = Convert.ChangeType(value, _type);
args.Value = converted;
}
public override void OnSetValue(LocationInterceptionArgs args) {
var @this = args.Instance;
var newValue = Convert.ToUInt64(args.Value);
var oldValue = Convert.ToUInt64(args.Binding.GetValue(ref @this, Arguments.Empty));
var value = (oldValue & ~_mask) | (newValue << BitOffset);
var converted = Convert.ChangeType(value, _type);
args.SetNewValue(converted);
}
}
有什么方法可以用值类型 struct
s 实现这个吗?
结构上的 LocationInterceptionAspect 在这里应该可以正常工作。
Bit1 的声明对于 Class 有点不同:
[FieldOffset(0)] [BitsAspect(1,1)] public byte Bit1;
对于结构:
[FieldOffset(0)] [BitsAspect(0,1)] public byte Bit1;
我敢打赌这会有所作为。
注意可变值类型,它们可以是 pure evil.