有什么方法可以避免C#中的Property内联优化?

Bri*_*sio 7 c# stack-trace

所以我有一个旨在实现INotifyPropertyChanged的PropertyBag类.为了使这段代码尽可能干净地工作并避免用户错误,我使用堆栈来获取属性名称.请参阅,如果属性名称与实际属性完全不匹配,那么您将失败并且我正在尝试保护它.

所以,这是该类的示例用法:

public class MyData : PropertyBag
{
    public MyData()
    {
        Foo = -1;
    }

    public int Foo
    {
        get { return GetProperty<int>(); }
        set { SetProperty(value); }
    }
}
Run Code Online (Sandbox Code Playgroud)

基本PropertyBag的重要代码在这里:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以现在你已经看到了我的代码,我可以告诉你这个问题......在某些情况下,在发布版本中,"MyData"构造函数中的"Foo"setter似乎正在优化为内联为SetProperty(-1).不幸的是,这个内联优化失败了我的SetProperty方法,因为我不再从属性调用它!失败.看来我不能以这种方式依赖StackTrace.

任何人都可以答:找出更好的方法来做到这一点,但仍然避免将"Foo"传递给GetProperty和SetProperty?
B:想办法告诉编译器在这种情况下不优化?

Mar*_*ell 14

在这里使用堆栈是缓慢且不必要的; 我只想使用:

get { return GetProperty<int>("Foo"); }
set { SetProperty("Foo", value); }
Run Code Online (Sandbox Code Playgroud)

(提示:我已经使用自定义属性模型做了很多工作;我知道这很有效......)

另一个替代方法是对象键(使用引用相等来比较) - 很多ComponentModel方法都是这样工作的,WF/WPF中的一些属性也是如此:

static readonly object FooKey = new object();
...
get { return GetProperty<int>(FooKey); }
set { SetProperty(FooKey, value); }
Run Code Online (Sandbox Code Playgroud)

当然,您可以声明键的类型(带有Name属性),并使用:

static readonly PropertyKey FooKey = new PropertyKey("Foo");
Run Code Online (Sandbox Code Playgroud)

等等; 然而,要回答这个问题:用它标记它(但要这样做):

[MethodImpl(MethodImplOptions.NoInlining)]
Run Code Online (Sandbox Code Playgroud)

要么

[MethodImpl(MethodImplOptions.NoOptimization)]
Run Code Online (Sandbox Code Playgroud)

要么

[MethodImpl(MethodImplAttributes.NoOptimization
    | MethodImplAttributes.NoInlining)]
Run Code Online (Sandbox Code Playgroud)