C# StackFrame在释放模式下表现不同
这是我的密码:C# StackFrame在释放模式下表现不同,c#,.net,C#,.net,这是我的密码: public class UserPreferences { /// <summary> /// The EMail signature. /// </summary> [UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")] public static string Signature {
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;
}
我曾经回答过一个类似的问题 简言之,这是一个非常糟糕的设计决策,因为您的方法是一个伪君子,它与不同的调用方进行不同的对话,但不公开地告诉它。您的API永远不应该依赖于调用它的人。此外,由于lambdas、
yield
和await
等语言特性,编译器可能会以意外的方式中断堆栈跟踪,因此,即使这在发布模式下工作,总有一天也会中断
您正在有效地构建一个复杂的间接机制,而不是使用设计用于将信息传递给方法-方法参数的语言功能
为什么要使用属性?你在别处读过吗
如果您不想重复“代码>电子邮件”作为参数为<代码> GETValue表达式< /代码>传递到<代码> GETValue,这将提取属性。这与您的解决方案类似,但非常明确:
[UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
public string Signature
{
get { return GetValue (prefs => prefs.Signature); }
set { SetValue (prefs => prefs.Signature, value); }
}
我看到您正在检查代码中的Thread.CurrentPrincipal
。同样,这不是一个很好的实践,因为客户端代码并不清楚访问属性会导致异常。对于支持您的代码(相信我)的人来说,这将是一场调试噩梦
相反,您应该将VTXIdentity
作为设置类构造函数的参数。这将确保调用代码知道您在此级别上强制执行安全性,并且根据定义知道从何处获取此令牌。此外,这还允许您在知道有问题时抛出异常,而不是在访问某些属性时抛出异常。这将帮助维护人员更早地捕获错误,就像编译错误比运行时错误更好一样
最后,虽然这是一个有趣的练习,但也有很多。你为什么认为你需要重新发明轮子?假设你的问题在关于你是否可以使用另一个库而不是滚动你自己的库的讨论中幸存下来。。。如果您发现自己正在使用C#5和.NET4.5,请查看该属性。使用CallerMemberName,您可以将GetValue()方法签名修改为
public static string GetValue([CallerMemberName] string callerName = "")
然后,该属性可以不带参数地调用GetValue(),您将根据需要将属性名称传递到GetValue()中“StackFrame信息在调试生成配置中的信息量最大。默认情况下,调试生成包含调试符号,而发布生成不包含调试符号。调试符号包含大多数用于构造StackFrame对象的文件、方法名、行号和列信息。“这是否意味着..此代码在生产中会失败,因为在生产中它将作为发布模式部署???为什么依赖StackFrame()在发布版本中?使用不同的设计!处理这样的用户预付费是非常繁重和过于复杂的。在线上应该有很多例子:你可以考虑MEF+ 1的目标。也可用于这种问题/设计选择是MEF-
public static string GetValue([CallerMemberName] string callerName = "")