How to prevent optimization on a class field in C# - c#

I have built an abstract class that is used to handle command line options for our products.
One need only to create a class inheriting from AbstractOptions, fill it with decorated fields and call the inherited Parse(args) method to have it automatically filled through reflection with values from the command line. Values that were not found on the command line retain their current (default) values.
Then, the application needs only to check the option fields to get their value. The AbstractOptions class provides more features, like help output, etc, but it is beside the point.
Short example:
public class SignalOptions: AbstractOptions
{
[Option("-i, --iterations", "Number of iterations (0 = infinite).")]
volatile public int NumberOfIterations;
[Option("-s, --silent", "Silent mode, only display final results.")]
volatile public bool Silent;
[Option("-w, --zwindow", "Window size for z-score analysis.")]
volatile public int ZWindow = 7;
[Option("-a, --zalert", "z-score value to consider as peak.")]
public double ZAlert = 2.1;
}
static void Main(string[] args)
{
var opts = new SignalOptions();
opts.Parse(args)
// If optimizations are turned off, SILENT will be written or not
// followind presence or absence of the --silent switch on the command line.
// If optimizations are turned on, SILENT will never be written.
// The reflection part is working fine. I suspect the problem is that
// the compiler of the jitter having never found this set anywhere simply inlines
// the value 'false' inthe if, because when I step on it, it shows me the value as
// true or false, but has the same behavior no matter what value opts.Silence has.
if( opts.Silent )
Console.Writeline("SILENT");
}
Now, the problem I have is that since the compiler does not find any code actually changing the values of the SignalOptions class, it simply inlines the values where they are used in the code. I have circumvent the issue by requiring that all 'option' fields in the class be volatile, so no optimization is applied, and it works fine, but unfortunately the volatile keyword is not valid on a double.
I have spent much time on the net trying to find a workaround, without success. Is there anyway to either prevent optimizations on the fields or otherwise fool the compiler/jitter into thinking they are used at runtime?
I also would like to put as less as possible the onus on the calling application.
Thanks

I have a local copy here with Parse written as the rather opaque:
public void Parse(string[] args)
{ // deliberately opaque, not that it would make any difference
string fieldName = (new string('S', 1) + "ilentX").Substring(0, 6);
GetType().GetField(fieldName).SetValue(this, true);
}
It works fine. I do not believe the problem is what you think it is.

Here is my guess:
Parse is running in a separate thread, but as your synchronization is somehow flawed, this makes the rest of code run without having the values set already.
This would also explain why you are seeing the correct values in the debugger.
Update (opinionated):
Having Parse run in a separate thread is very weird, and should be considered a design flaw. Sounds like someone was thinking 'Reflection is slow, let's put it in a separate thread'.

Related

Private Set property not retaining its new value

Working on a problem for a test application I am building, and I can't seem to work out what to do. The app is essentially a questionnaire that is to be passed between two different people using the same device.
However, when I have a private setter for CurrentQuestion, the value never stays modified when being sent across to the new version of the activity. It always retains its original value of 1 (all other values stay modified though). When debugging though, I do see the value of the property increment by 1, it is just not retained.
As soon as I remove the private setter this resolves itself and it increments like normal, but I know this is bad practice, so I would like to find the correct way to do it.
Any help or guidance would be much appreciated, as I feel like I have tried a huge variety of different methods with no luck.
Setting an auto-poroperty like this assumes that all access and modification to that property will be done directly though the property itself, as opposed to using a method like you're doing to increment this property. Based on what you're doing here I would recommend this possible solution to your problem.
Set a backing field for the property and increment that in your NextQuestion method.
private int _currentQuestion;
public int CurrentQuestion => _currentQuestion;
public void NextQuestion()
{
_currentQuestion++;
}

C# assignment in constructor to member ... doesn't change it

I have a simple class intended to store scaled integral values
using member variables "scaled_value" (long) with a "scale_factor".
I have a constructor that fills a new class instance with a decimal
value (although I think the value type is irrelevant).
Assignment to the "scaled_value" slot appears... to not happen.
I've inserted an explicit assignment of the constant 1 to it.
The Debug.Assert below fails... and scaled_value is zero.
On the assertion break in the immediate window I can inspect/set using assignment/inspect "scale_factor"; it changes as I set it.
I can inspect "scaled_value". It is always zero. I can type an
assignment to it which the immediate window executes, but its value
doesn't change.
I'm using Visual Studio 2017 with C# 2017.
What is magic about this slot?
public class ScaledLong : Base // handles scaled-by-power-of-ten long numbers
// intended to support equivalent of fast decimal arithmetic while hiding scale factors from user
{
public long scaled_value; // up to log10_MaxLong digits of decimal precision
public sbyte scale_factor; // power of ten representing location of decimal point range -21..+21. Set by constructor AND NEVER CHANGED.
public byte byte_size; // holds size of value in underlying memory array
string format_string;
<other constructors with same arguments except last value type>
public ScaledLong(sbyte sf, byte size, string format, decimal initial_value)
{
scale_factor = sf;
byte_size = size;
format_string = format;
decimal temp;
sbyte exponent;
{ // rip exponent out of decimal value leaving behind an integer;
_decimal_structure.value = initial_value;
exponent = (sbyte)_decimal_structure.Exponent;
_decimal_structure.Exponent = 0; // now decimal value is integral
temp = _decimal_structure.value;
}
sbyte sfDelta = (sbyte)(sf - exponent);
if (sfDelta >= 0)
{ // sfDelta > 0
this.scaled_value = 1;
Debug.Assert(scaled_value == 1);
scaled_value = (long)Math.Truncate(temp * DecimalTenToPower[sfDelta]);
}
else
{
temp = Math.Truncate(temp / DecimalHalfTenToPower[-sfDelta]);
temp += (temp % 2); /// this can overflow for value at very top of range, not worth fixing; note: this works for both + and- numbers (?)
scaled_value = (long)(temp / 2); // final result
}
}
The biggest puzzles often have the stupidest foundations. This one is a lesson in unintended side effects.
I found this by thinking about, wondering how in earth a member can get modified in unexpected ways. I found the solution before I read #mjwills comment, but he was definitely sniffing at the right thing.
What I left out (of course!) was that I had just coded a ToString() method for the class... that wasn't debugged. Why did I leave it out? Because it obviously can't affect anything so it can't be part of the problem.
Bzzzzt! it used the member variable as a scratchpad and zeroed it (there's the side effect); that was obviously unintended.
When this means is that when code the just runs, ToString() isn't called and the member variable DOES get modified correctly. (I even had unit tests for the "Set" routine checked all that and they were working).
But, when you are debugging.... the debugger can (and did in this case) show local variables. To do that, it will apparently call ToString() to get a nice displayable value. So the act of single stepping caused ToSTring() to get called, and its buggy scratch variable assignment zeroed out the slot after each step call.
So it wasn't a setter that bit me. It was arguably a getter. (Where is FORTRAN's PURE keyword when you need it?)
Einstein hated spooky actions at a distance. Programmers hate spooky side effects at a distance.
One wonders a bit at the idea of the debugger calling ToString() on a class, whose constructor hasn't finished. What assertions about the state of the class can ToString trust, given the constructor isn't done? I think the MS debugger should be fixed. With that, I would have spent my time debugging ToString instead of chasing this.
Thanks for putting up with my question. It got me to the answer.
If you still have a copy of that old/buggy code it would be interesting to try to build it under VS 2019 and Rider (hopefully the latest, 2022.1.1 at this point) with ReSharper (built in) allowed to do the picky scan and with a .ruleset allowed to bitch about just about anything (just for the 1st build - you'll turn off a lot but you need it to scream in order to see what to turn off). And with .NET 5.0 or 6.0
The reason I mention is that I remember some MS bragging about doing dataflow analysis to some degree in 2019 and I did see Rider complaining about some "unsafe assignments". If the old code is long lost - never mind.
CTOR-wise, if CTOR hasn't finished yet, we all know that the object "doesn't exist" yet and has invalid state, but to circumvent that, C# uses default values for everything. When you see code with constant assignments at the point of definition of data members that look trivial and pointless - the reason for that is that a lot of people do remember C++ and don't trust implicit defaults - just in case :-)
There is a 2-phase/round initialization sequence with 2 CTOR-s and implicit initializations in-between. Not widely documented (so that people with weak hearts don't use it :-) but completely deterministic and thread-safe (hidden fuses everywhere). Just for the sake of it's stability you never-ever want to have a call to any method before the 2 round is done (plain CTOR done still doesn't mean fully constructed object and any method invocation from the outside may trigger the 2nd round prematurely).
1st (plain) CTOR can be used in implicit initializations before the 2nd runs => you can control the (implicit) ordering, just have to be careful and step through it in debugger.
Oh and .ToString normally shouldn't be defined at all - on purpose :-) It's de-facto intrinsic => compiler can take it's liberties with it. Plus, if you define it, pretty soon you'll be obliged to support (and process) format specifiers.
I used to define ToJson (before big libs came to fore) to provide, let's say a controllable printable (which can also go over the wire and is 10-100 times faster than deserialization). These days VS debugger has a collection of "visualizers" and an option to tell debugger to use it or not (when it's off then it will jerk ToString's chain if it sees it.
Also, it's good to have dotPeek (or actual Reflector, owned by Redgate these days) with "find source code" turned off. Then you see the real generated code which is sometimes glorious (String is intrinsic and compiler goes a few extra miles to optimize its operations) and sometimes ugly (async/await - total faker, inefficient and flat out dangerous - how do you say "deadlock" in C# :-) - not kidding) but you need to to be able to see the final code or you are driving blind.

What makes the Visual Studio debugger stop evaluating a ToString override?

Environment: Visual Studio 2015 RTM. (I haven't tried older versions.)
Recently, I've been debugging some of my Noda Time code, and I've noticed that when I've got a local variable of type NodaTime.Instant (one of the central struct types in Noda Time), the "Locals" and "Watch" windows don't appear to call its ToString() override. If I call ToString() explicitly in the watch window, I see the appropriate representation, but otherwise I just see:
variableName {NodaTime.Instant}
which isn't very useful.
If I change the override to return a constant string, the string is displayed in the debugger, so it's clearly able to pick up that it's there - it just doesn't want to use it in its "normal" state.
I decided to reproduce this locally in a little demo app, and here's what I've come up with. (Note that in an early version of this post, DemoStruct was a class and DemoClass didn't exist at all - my fault, but it explains some comments which look odd now...)
using System;
using System.Diagnostics;
using System.Threading;
public struct DemoStruct
{
public string Name { get; }
public DemoStruct(string name)
{
Name = name;
}
public override string ToString()
{
Thread.Sleep(1000); // Vary this to see different results
return $"Struct: {Name}";
}
}
public class DemoClass
{
public string Name { get; }
public DemoClass(string name)
{
Name = name;
}
public override string ToString()
{
Thread.Sleep(1000); // Vary this to see different results
return $"Class: {Name}";
}
}
public class Program
{
static void Main()
{
var demoClass = new DemoClass("Foo");
var demoStruct = new DemoStruct("Bar");
Debugger.Break();
}
}
In the debugger, I now see:
demoClass {DemoClass}
demoStruct {Struct: Bar}
However, if I reduce the Thread.Sleep call down from 1 second to 900ms, there's still a short pause, but then I see Class: Foo as the value. It doesn't seem to matter how long the Thread.Sleep call is in DemoStruct.ToString(), it's always displayed properly - and the debugger displays the value before the sleep would have completed. (It's as if Thread.Sleep is disabled.)
Now Instant.ToString() in Noda Time does a fair amount of work, but it certainly doesn't take a whole second - so presumably there are more conditions that cause the debugger to give up evaluating a ToString() call. And of course it's a struct anyway.
I've tried recursing to see whether it's a stack limit, but that appears not to be the case.
So, how can I work out what's stopping VS from fully evaluating Instant.ToString()? As noted below, DebuggerDisplayAttribute appears to help, but without knowing why, I'm never going to be entirely confident in when I need it and when I don't.
Update
If I use DebuggerDisplayAttribute, things change:
// For the sample code in the question...
[DebuggerDisplay("{ToString()}")]
public class DemoClass
gives me:
demoClass Evaluation timed out
Whereas when I apply it in Noda Time:
[DebuggerDisplay("{ToString()}")]
public struct Instant
a simple test app shows me the right result:
instant "1970-01-01T00:00:00Z"
So presumably the problem in Noda Time is some condition that DebuggerDisplayAttribute does force through - even though it doesn't force through timeouts. (This would be in line with my expectation that Instant.ToString is easily fast enough to avoid a timeout.)
This may be a good enough solution - but I'd still like to know what's going on, and whether I can change the code simply to avoid having to put the attribute on all the various value types in Noda Time.
Curiouser and curiouser
Whatever is confusing the debugger only confuses it sometimes. Let's create a class which holds an Instant and uses it for its own ToString() method:
using NodaTime;
using System.Diagnostics;
public class InstantWrapper
{
private readonly Instant instant;
public InstantWrapper(Instant instant)
{
this.instant = instant;
}
public override string ToString() => instant.ToString();
}
public class Program
{
static void Main()
{
var instant = NodaConstants.UnixEpoch;
var wrapper = new InstantWrapper(instant);
Debugger.Break();
}
}
Now I end up seeing:
instant {NodaTime.Instant}
wrapper {1970-01-01T00:00:00Z}
However, at the suggestion of Eren in comments, if I change InstantWrapper to be a struct, I get:
instant {NodaTime.Instant}
wrapper {InstantWrapper}
So it can evaluate Instant.ToString() - so long as that's invoked by another ToString method... which is within a class. The class/struct part seems to be important based on the type of the variable being displayed, not what code needs
to be executed in order to get the result.
As another example of this, if we use:
object boxed = NodaConstants.UnixEpoch;
... then it works fine, displaying the right value. Colour me confused.
Update:
This bug has been fixed in Visual Studio 2015 Update 2. Let me know if you are still running into problems evaluating ToString on struct values using Update 2 or later.
Original Answer:
You are running into a known bug/design limitation with Visual Studio 2015 and calling ToString on struct types. This can also be observed when dealing with System.DateTimeSpan. System.DateTimeSpan.ToString() works in the evaluation windows with Visual Studio 2013, but does not always work in 2015.
If you are interested in the low level details, here's what's going on:
To evaluate ToString, the debugger does what's known as "function evaluation". In greatly simplified terms, the debugger suspends all threads in the process except the current thread, changes the context of the current thread to the ToString function, sets a hidden guard breakpoint, then allows the process to continue. When the guard breakpoint is hit, the debugger restores the process to its previous state and the return value of the function is used to populate the window.
To support lambda expressions, we had to completely rewrite the CLR Expression Evaluator in Visual Studio 2015. At a high level, the implementation is:
Roslyn generates MSIL code for expressions/local variables to get the values to be displayed in the various inspection windows.
The debugger interprets the IL to get the result.
If there are any "call" instructions, the debugger executes a
function evaluation as described above.
The debugger/roslyn takes this result and formats it into the
tree-like view that's shown to the user.
Because of the execution of IL, the debugger is always dealing with a complicated mix of "real" and "fake" values. Real values actually exist in the process being debugged. Fake values only exist in the debugger process. To implement proper struct semantics, the debugger always needs to make a copy of the value when pushing a struct value to the IL stack. The copied value is no longer a "real" value and now only exists in the debugger process. That means if we later need to perform function evaluation of ToString, we can't because the value doesn't exist in the process. To try and get the value we need to emulate execution of the ToString method. While we can emulate some things, there are many limitations. For example, we can't emulate native code and we can't execute calls to "real" delegate values or calls on reflection values.
With all of that in mind, here is what's causing the various behaviors you are seeing:
The debugger isn't evaluating NodaTime.Instant.ToString -> This is
because it is struct type and the implementation of ToString can't
be emulated by the debugger as described above.
Thread.Sleep seems to take zero time when called by ToString on a
struct -> This is because the emulator is executing ToString.
Thread.Sleep is a native method, but the emulator is aware
of it and just ignores the call. We do this to try and get a value
to show to the user. A delay wouldn't be helpful in this case.
DisplayAttibute("ToString()") works. -> That is confusing. The only
difference between the implicit calling of ToString and
DebuggerDisplay is that any time-outs of the implicit ToString
evaluation will disable all implicit ToString evaluations for that
type until the next debug session. You may be observing that
behavior.
In terms of the design problem/bug, this is something we are planning to address in a future release of Visual Studio.
Hopefully that clears things up. Let me know if you have more questions. :-)

How to avoid property recursion

This hit me recently on a project I was working on. Most people are familiar with property recursion:
public int Test
{
get { return this.test; }
set { this.Test = value; }
}
private int test;
You accidentally put an upper-case T in this setter, and you've opened yourself up to a StackoverflowException. What's worse is if you've not defined it, often visual studio will auto-correct the casing for you to the invalid state.
I did something similar however in a constructor recently:
public TestClass(int test)
{
this.Test = Test;
}
Unfortunately here you don't get a StackOverflowException, now you've got a programming error. In my case this value was passed to a WebService that instead used a default value (which wasn't 0) which caused me to miss the fact I had incorrectly assigned it. Integration tests all passed because this service didn't say
"Hey you forgot this really important field!"
What steps can I take to avoid this sort of behaviour? I've always been advised against defining variables like the following, and I don't like them personally, but I can't think of any other options:
private int _test;
private int mTest;
EDIT
Reasons that the underscore or m prefix are undesirable normally that I can think of are:
Readability
Slightly more difficult to scroll through members if you're inheriting from 3rd party classes as you get a mix of styles.
Best way is to use "Auto implemented properties" here.
public int Test { get; set; }
If not possible to use "Auto implemented properties" for some reason use _ prefix(I don't prefer though).
If you also don't prefer to use some prefixes, then you have other option. You don't have to write the property code by hand. Let the IDE do it for you; that way you can avoid careless mistakes. (I don't know how I missed this in original answer)
Just type
private int test;
Select the field, Right click Refactor->Encapsulate Field. IDE will generate property snippet for you as below.
public int Test
{
get { return test; }
set { test = value; }
}
You don't need to bother clicking the context menu. If you prefer keyboard, shortcut is Ctrl + R + E.
Or get a Resharper, It will point your silly mistake immediately.
Integration tests all passed
Then they weren't exhaustive enough tests. If there's an error that wasn't discovered by the tests, then you've got another test to write.
That's really the only automated solution here. The compiler isn't going to complain, because the code is structurally and syntactically correct. It's just not logically correct at runtime.
You can define naming standards, even use tools like StyleCop to attempt to enforce those standards. That would probably allow you to cover a lot, though it's not an ironclad solution and errors can still get through. Personally I agree with you that decorating variable names is unsightly in the code. Perhaps in some cases it's a valid tradeoff?
Ultimately, automated tests are your defense against these kinds of errors. At its simplest, if an error gets through your tests and into production then the response should be:
Write a test to reproduce the error.
Fix the error.
Use the test to validate the fix.
Granted, that only covers that one case, not every property definition in your code. But if this is happening a lot then you may have a personnel problem and not a technical problem. Somebody on the team is, well, sloppy. The solution to that problem may not be a technical one.
Use code snippets.
For every property backed by a private field, use a custom code snippet you have created, instead of writing it up from scratch or letting IntelliSense do the job (poorly).
After all, this problem is about conventions and discipline, rather than language design. The case sensitive nature of C# and the subperfect code completion in Visual Studio are the reason we make these mistakes, not our lack of knowledge and design.
You best bet here is to eliminate the chance of accidents and having a predefined way of writing these repetitive things correctly is the best way to go. It also is much more automated compared to remembering conventions and enforcing them by hand.
There is a default code snippet in Visual Studio for this. Type propfull and hit Tab, then specify the instance variable name and the property name and you're good to go.
In some cases you cannot get around setters and getters. But maybe you don't need the setters and getters if you follow the Tell, Don't Ask principle? It basically says to prefer having the object that has the data do the work, not some other object query a lot from the data object, make decisions, and then write data back to the data object. See http://martinfowler.com/bliki/TellDontAsk.html
Could you not just write a test to cover this?
int constructorValue = 4;
TestClass test = new TestClass(constructorValue);
Assert.Equals(test.Test, constructorValue);
You may not want to write tests immediately to cover yourself from future wobbles, but you've found a bug, why not protect yourself from it again?
For the record, if I need a private field to store the value for a pulic getter/setter, I always underscore it. There's just something an underscore that screams privacy!
public string Test
{
get { return _test; }
set { _test = value; }
}
private string _test;

Multithreading or something different

This is the first time I face a problem like this. Not being this my profession but only my hobby, I have no previous references.
In my program I have added one by one several functions to control a machine. After I added the last function (temperature measurement), I have started experiencing problems on other functions (approx. 8 of them running all together. The problem I am experiencing is on a chart (RPM of a motor) that is not related to this function but is affected by it. You see the difference between these two charts with and without the temperature measurement running. The real speed of the motor is the same in both charts but in the second one I loose pieces on the fly because the application slows down.
Without the temperature function.
With the temperature function
Particularly this function is disturbing the above control and I think is because the work load is becoming heavy for the application and or because I need sampling so there is some time waiting to get them:
private void AddT(decimal valueTemp)
{
sumTemp += valueTemp;
countTemp += 1;
if (countTemp >= 20) //take 20 samples and make average
{
OnAvarerageChangedTemp(sumTemp / countTemp);
sumTemp = 0;
countTemp = 0;
}
}
private void OnAvarerageChangedTemp(decimal avTemp)
{
float val3 = (float)avTemp;
decimal alarm = avTemp;
textBox2.Text = avTemp.ToString("F");
if (alarm > 230)
{
System.Media.SoundPlayer player = new System.Media.SoundPlayer();
player.Stream = Properties.Resources.alarma;
player.Play();
timer4.Start();
}
else
{
timer4.Stop();
panel2.BackColor = SystemColors.Control;
}
}
I am wondering if running this function on a different thread would solve the problem and how I can do that? Or if there is a different way to solve the problem.Sample code will be appreciated.
Update, added method call.
This is how I call the method AddT
if (b != "")
{
decimal convTemp; //corrente resistenza
decimal.TryParse(b, out convTemp);
AddT(convTemp);}
This is how I receive the data from the serial and pass it to the class that strips out unwonted chars and return values to the different variables.
This is the class that strips out the unwonted chars and return the values.
And this is how I manage the serial incoming data. Please do not laugh at me after seeing my coding. I do a different job and I am learning on my own.
It's very hard to tell if there's anything wrong and what it might be - it looks like subtle problem.
However, it might be easier to get a handle on these things if you refactor your code. There are many things in the code you've shown that make it harder than necessary to reason about what's happening.
You're using float and decimal - float isn't that accurate but small and fast; decimal (tries) to be precise but especially is predictable since it rounds errors the way a human might in base-10 - but it is quite slow, and is usually intended for calculations where precise reproducibility is necessary (e.g. financial stuff). You should probably use double everywhere.
You've got useless else {} code in the Stripper class.
Your Stripper is an instatiable class, when it should simply be a static class with a static method - Stripper is stateless.
You're catching exceptions just to rethrow them.
You're using TryParse, and not checking for success. Normally you'd only use TryParse if you (a) expect parsing to fail sometimes, and (b) can deal with that parse failure. If you don't expect failure or can't deal with it, you're better off with a crash you learn about soon than a subtly incorrect values.
In stripper, you're duplicating variables such as _currentMot, currentMot, and param4 but they're identical - use only the parameter, and give it a logical name.
You're using out parameters. It's almost always a better idea to define a simple struct and return that instead - this also allows you to ensure you can't easily mix up variable names, and it's much easier to encapsulate and reuse functionality since you don't need to duplicate a long call and argument definition.
Your string parsing logic is too fragile. You should probably avoid Replace entirely, and instead explicitly make a Substring without the characters you've checked for, and you have some oddly named things like test1 and test2 which refer to a lastChar that's not the last character - this might be OK, but better names can help keep things straight in your head too.
You have incorrect code comments (decimal convTemp; //corrente resistenza). I usually avoid all purely technical code comments; it's better to use descriptive variable names which are another form of self-documenting code but one in which the compiler can at least check if you use them consistently.
Rather that return 4 possibly empty values, your Stripper should probably accept a parameter "sink" object on which it can call AddT AddD and AddA directly.
I don't think any of the above will fix your issue, but I do believe they're help keep your code a little cleaner and (in the long run) make it easier to find the issues.
your problem is in the parsing of the values you have
decimal.TryParse(a, out convRes);
AddA(convRes);
and don't check for failed values you only accept the value if it returns true
if(decimal.TryParse(a, out convRes))
{
AddA(convRes);
}
you may have more errors but this one is making you process 0 values every time the TryParse fails.

Categories

Resources