StackFrame behaves differently in release mode

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, the StackFrame works differently in release mode and debug mode.

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

But in Release mode, the property name is GetUserPreferenceValueTest, because it is a testing method that makes calls as clients.

Therefore, my code works in debug mode, but does not work 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? 
+8
c #
source share
2 answers

I answered the same question once, please read my answer here .

In short, this is a very bad design decision, because your method is a hypocrite - it speaks different for different subscribers, but does not speak about it openly. Your API should never, never rely on whoever calls it. In addition, the compiler may unexpectedly break the stack trace due to language functions such as lambdas, yield and await , so even if it worked in Release mode, it would certainly break once.

You effectively create a complex mechanism of indirection instead of using a language function designed to transmit information to methods - method parameters .

Why are you using attributes? Do you read them elsewhere?

If you do this and you do not want to repeat "Email" as a parameter for the GetValue call and attribute value, you can consider passing the Expression<> property to GetValue , which will retrieve the attribute. This seems like 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 that you are checking Thread.CurrentPrincipal in your code. Again, this is not a good practice, because it is not obvious to the client code that access to the property can lead to an exception. It will be a debugging nightmare for someone who supports your code (and believe me, your code can work for many years in the production process, long after you switch to another project ).

Instead, you should make the VTXIdentity parameter in your settings class constructor. This will ensure that the calling code knows ensure security at this level and, by definition, knows where to get this token. In addition, it allows you to rule out as soon as you know something is wrong. , but not when accessing some property. This will help administrators catch errors earlier, just as compilation errors are better than runtime errors.

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

+7
source share

Assuming your problem survives, discuss whether you can just use another library and not collapse your own ... if you find yourself using C # 5 and .NET 4.5, look at CallerMemberName . With CallerMemberName, you can change your signature of the GetValue () method as

 public static string GetValue([CallerMemberName] string callerName = "") 

Then the property can call GetValue () without a parameter, and you will get the property name passed to GetValue () as you want.

+4
source share

All Articles