的StackFrame表现不同的方式在释放模式 [英] StackFrame behaving differently in release mode

查看:107
本文介绍了的StackFrame表现不同的方式在释放模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我的code:

 公共类用户preferences
{
    ///<总结>
    ///电子邮件签名。
    ///< /总结>
    [网友preferenceProperty(类别=电子邮件,默认值=我的默认值)]
    公共静态特征码
    {
        得到
        {
            返回用户preferenceManager.GetValue();
        }

        组
        {
            用户preferenceManager.SetValue(值);
        }
    }
}

公共静态字符串的GetValue()
{
    如果(((VTXPrincipal)Thread.CurrentPrincipal中).VTXIdentity.OperatorID == NULL)
    {
        抛出新的异常(缺少操作员ID);
    }

    字符串值=的String.Empty;

    VAR帧=新的StackFrame(1); *****< ------这里问题.....

    VAR属性= frame.GetMethod();
    VAR参数propertyName = property.Name.Split(_)[1];
    VAR类型= property.DeclaringType; *****< ------这里问题.....
    如果(型!= NULL)
    {
        VAR用户preference = typeof运算(使用preferences).GetProperty(propertyName的).GetCustomAttributes(真).FirstOrDefault()作为用户preferencePropertyAttribute;

        如果(用户preference!= NULL)
        {
            串类=用户preference.Category;
            字符串描述= propertyName的;
            值=的GetValue(类别,说明,((VTXPrincipal)Thread.CurrentPrincipal中).VTXIdentity.OperatorID);
            如果(价值== NULL)
            {
                //总是返回的东西
                返回用户preference.DefaultValue;
            }
        }
        其他
        {
            抛出新的异常(丢失的用户preference);
        }
    }

    返回值;
}
 

在GetValue方法,的StackFrame的工作方式不同在释放模式与调试模式。

在调试模式下,我得到正确的属性名作为签名

但在发布模式,属性名称的getUser preferenceValueTest因为这是测试方法,使通话的客户。

还有我的前code工作在调试模式,但未能在释放模式。

 问:我如何使用的StackFrame正确因此它可以在调试与发行模式。

问:是否有任何其他方式来获得调用属性名称和相关信息在运行时?
 

解决方案

我回答过类似的问题出现,请读到这里我的答案

总之,这是一个非常糟糕的设计决定,因为你的方法是一个伪君子,它谈到不同的不同的来电者,但并不能说明它打开。你的API应该的永远不要的依靠谁调用它。此外,编译器可以以意想不到的方式打破堆栈跟踪,由于像lambda表达式语言特性,收益率等待,因此,即使这个曾在发行模式下,它肯定会打破的一天。

您正在有效地构建一个复杂的间接机制,而不是使用语言特性的设计作为将信息传递给方法 - 方法的参数

为什么要使用属性?你是否在其他地方阅读?

如果你这样做,你不希望重复电子邮件既作为参数传递给的GetValue 通话和属性值,你可以考虑通过属性防爆pression<> 的GetValue ,这将提取的属性。这类似于解决方案,但它是明确的:

  [用户preferenceProperty(类别=电子邮件,默认值=我的默认值)]
公共特征码
{
    {返回的GetValue(preFS => prefs.Signature); }
    集合{的SetValue(preFS => prefs.Signature,价值); }
}
 

这样的回答显示了如何实现这一点。

我看你在你的code检查 Thread.CurrentPrincipal中。再次,这是不是一个非常好的做法,因为它不是的很明显的客户端code的访问属性会导致异常。这将是一个调试噩梦的人谁支持你的code(相信我,的您code可以运行数年的生产,经过长期移动到另一个项目)。

相反,你应该让 VTXIdentity 参数以设置类构造函数。这将确保调用code 知道您执行安全这个层面上,并通过定义知道从何处获得此令牌。此外,这可以让你抛出一个异常只要你知道什么是错的,而不是访问某些属性时。这将有助于维护捕获错误较早很像编译错误比运行时错误的更好。

最后,虽然这是一个有趣的练习,也有用于存储和大量的高性能和测试的解决方案阅读在C#中配置。为什么你认为你需要推倒重来?

Here is my code:

public class UserPreferences
{
    /// <summary>
    /// The EMail signature.
    /// </summary>
    [UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
    public static string Signature
    {
        get
        {
            return UserPreferenceManager.GetValue();
        }

        set
        {
            UserPreferenceManager.SetValue(value);
        }
    }
}

public static string GetValue()
{
    if (((VTXPrincipal)Thread.CurrentPrincipal).VTXIdentity.OperatorID == null)
    {
        throw new Exception("Missing Operator ID");
    }

    string value = string.Empty;

    var frame = new StackFrame(1);  ***** <------ problem here.....

    var property = frame.GetMethod();
    var propertyname = property.Name.Split('_')[1];
    var type = property.DeclaringType;   ***** <------ problem here.....
    if (type != null)
    {
        var userPreference = typeof(UserPreferences).GetProperty(propertyname).GetCustomAttributes(true).FirstOrDefault() as UserPreferencePropertyAttribute;

        if (userPreference != null)
        {
            string category = userPreference.Category;
            string description = propertyname;
            value = GetValue(category, description, ((VTXPrincipal)Thread.CurrentPrincipal).VTXIdentity.OperatorID);
            if (value == null)
            {
                // always return something
                return userPreference.DefaultValue;
            }
        }
        else
        {
            throw new Exception("Missing User Preference");
        }
    }

    return value;
}

Inside the GetValue method, StackFrame works differently in release mode vs. debug mode.

In debug mode, I correctly get the property name as signature

But in Release mode, property name is GetUserPreferenceValueTest because this is the test method that makes the calls as clients.

There fore my code works in debug mode but fails in release mode.

Q. How can I use StackFrame properly so it works in Debug vs. Release modes. 

Q. Is there any other way to get calling property name and related information at run time?

解决方案

I answered a similar question once, please read my answer here.

In short, this is a very bad design decision because your method is a hypocrite—it talks different to different callers but doesn't tell it in open. Your API should never, ever rely on who calls it. Also, the compiler can break the stack trace in an unexpected way due to language features like lambdas, yield and await, so even if this worked in Release mode, it would certainly break some day.

You're effectively building a complex indirection mechanism instead of using language feature designed for passing information to methods—method parameters.

Why do you use attributes? Do you read them elsewhere?

If you do, and you don't want to repeat "Email" both as parameter to GetValue call and attribute value, you may consider passing a property Expression<> to GetValue, which will extract the attribute. This is similar to your solution, but it is explicit:

[UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
public string Signature
{
    get { return GetValue (prefs => prefs.Signature); }
    set { SetValue (prefs => prefs.Signature, value); }
}

This answer shows how to implement this.

I see you are checking Thread.CurrentPrincipal in your code. Again, this is not a really good practice because it is not obvious to client code that accessing a property can result in an exception. This is going to be a debugging nightmare for someone who supports your code (and trust me, your code may run for years in production, long after you move onto another project).

Instead, you should make VTXIdentity a parameter to your settings class constructor. This will ensure the calling code knows you enforce security on this level and by definition knows where to obtain this token. Also, this allows you to throw an exception as soon as you know something is wrong, rather than when accessing some property. This will help maintainers catch errors earlier—much like compile errors are better than runtime errors.

Finally, while this is a fun exercise, there are plenty performant and tested solutions for storing and reading configuration in C#. Why do you think you need to reinvent the wheel?

这篇关于的StackFrame表现不同的方式在释放模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆