So I have a PropertyBag class that is intended to implement INotifyPropertyChanged. In order to make this code work as cleanly as possible and to avoid user error, I am using the stack to get the property name. See, if the property name doesn’t match the actual property exactly, then you will have a failure and I am trying to protect from that.
So, here is an example usage of the class:
public class MyData : PropertyBag { public MyData() { Foo = -1; } public int Foo { get { return GetProperty<int>(); } set { SetProperty(value); } } }
The important code for the base PropertyBag is here:
public abstract class PropertyBag : INotifyPropertyChanged { protected T GetProperty<T>() { string propertyName = PropertyName((new StackTrace()).GetFrame(1)); if (propertyName == null) throw new ArgumentException('GetProperty must be called from a property'); return GetValue<T>(propertyName); } protected void SetProperty<T>(T value) { string propertyName = PropertyName((new StackTrace()).GetFrame(1)); if (propertyName == null) throw new ArgumentException('SetProperty must be called from a property'); SetValue(propertyName, value); } private static string PropertyName(StackFrame frame) { if (frame == null) return null; if (!frame.GetMethod().Name.StartsWith('get_') && !frame.GetMethod().Name.StartsWith('set_')) return null; return frame.GetMethod().Name.Substring(4); } }
So now that you have seen my code, I can tell you the problem… In some cases under release build, the ‘Foo’ setter in the ‘MyData’ constructor appears to be getting optimized to inline as SetProperty(-1). Unfortunately, this inline optimization fails out my SetProperty method because I am no longer calling it from a property! FAIL. It appears that I cannot rely on the StackTrace in this way.
Can anyone A: Figure out a better way to do this but still avoid passing in ‘Foo’ to GetProperty and SetProperty?
B: Figure out a way to tell the compiler to not optimize in this case?
Using the stack here is slow and unnecessary; I would simply use:
(hint: I’ve done a lot of work with custom property models; I know that this works well…)
Another alternative is an object key (use reference equality to compare) – a lot of
ComponentModelworks this way, as do some of the properties in WF/WPF:Of course, you could declare a type for the keys (with a
Nameproperty), and use that:etc; however, to answer the question: mark it (but don’t do this) with:
or
or