C# synonymous enum handling - c#

This is either too clever by half or not clever enough by 62.784%. For odd reasons, our product management decided they wanted to rename some of our enum values and how they serialize. After a couple of builds they decided they wanted it to be backwards compatible - i.e. read and process old serializations to the new values.
I thought I'd try declaring the new name in the enum first, then declaring OldName = NewName just after as a synonym, hoping that the equivalency would get worked out in the wash in favor of the first declaration and it would automagically translate old to new with Enum.Parse.
I worked up a little sample app like so:
public enum syns
{
Zero,
One,
Two,
Three = Two,
Four,
};
public string SynTest()
{
string result;
syns synTest2 = (syns)syns.Two, synTest3;
bool okay = Enum.TryParse<syns>("Three", out synTest3);
result = (okay).ToString() + "," + (synTest2 == synTest3).ToString() + "," + synTest2.ToString() + "," + synTest3.ToString() + ",";
synTest3 = (syns)Enum.Parse(typeof(syns), "Three");
result += synTest3.ToString();
return result;
}
and got what I wanted. The old name "Three" parsed, and when the parsed value was evaluated it produced the new name Two every which way. Yay.
So I used the technique in our actual code (a much longer enum, with lots of app-specific names/values, etc). Worked on my machine, so I checked it in.
The problem we're having is that there doesn't appear to be any consistency in how this is handled. The build got to QA, and (the equivalent of) "Three" parsed and stayed as Three throughout (old name) rather than evaluating to the new version Two.
After pulling on this thread for a while, it seems like about 50% of the machines we've tried it on process it the way my machine did (new value prevailing) and 50% skew to the old name.
I tried pulling all of the test cases into a test.aspx page, and my test.aspx page behaves differently than the underlying assemblies. And in the test.aspx page, the enum above behaves differently from the actual enum from our code base.
Any hints as to what determines how evaluations of synonym enums lean?
Any ideas why the same assemblies would change behavior machine to machine? All the machines are set to target framework 4.5.1, and at least on the couple I compared it seemed they were at the same patch level.
Even on a machine where I got the desired behavior, pulling the same declaration into a test.aspx changed the behavior, so I was wondering if this is fickle on a file-by-file basis.

This is "clearly" documented under Enum.ToString:
Notes to Callers
If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.
(my emphasis)
This is documented to have unspecified behavior. There may in fact be a observable (seemingly) consistent behavior on one machine depending on the .NET runtime version, .NET hotfixes installed etc. etc. but you cannot make any guarantees that it will continue to behave like that tomorrow or next week.
In short, you cannot do it this way, you need to find another way to handle the aliasing.

Related

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.

Should I leave this static variable, or refactor it?

A previous developer placed a static string called "Qry" in a "god" class in a project I inherited.
The developer then used this static variable in every single place throughout the program that a single db query string is built and used.
For instance:
SomeGodClass.Qry = "select count(1) from AddressBook where Name = '" + txtName.Text.Trim(' ') +
"' and Group_Name = '" + txtGroupName.Text.Trim(' ') + "'";
int count = sqlHelper.ExecuteScalar(SomeGodClass.Qry);
Thus, this variable is referenced exactly 626 times, most with a different query being assigned. There are other static variables like this that he used - probably 50 of them - but this is the most predominant.
My first instinct is to remove this static string and rework all 626 usages. However, I don't know if this is a bad enough practice to take the time to do it.
Thus, my question is: Is this an acceptable use of a static string, especially when taking into consideration the amount of work refactoring would take?
Don't see any problem of using static here, at least judging from the code I see. But do not use TextBox concatenation !
Use Parameters instead.
That is most important refactoring I can think of while looking on the code provided.
Why do we always prefer using parameters in SQL statements?
You should definitely refactor this. It looks like SomeGodClass.Qry was ment to be a constant of some kind, but what good is a constant if you keep reassigning it? Now you never know what's its value, unless you have just overwritten it.
Just use a local variable query instead, and use parameters (like Tigran said)
One of the main issues with using a static member for code like this is that at first glance, it looks fine (if a little redundant).
SomeGodClass.Qry = /* Some Query */;
int count = sqlHelper.ExecuteScalar(SomeGodClass.Qry);
It assigns a value, then uses it, great. The problem comes if you start introducing threads into your application. Suddenly, the static is being assigned and used from multiple threads and there's no guarantee that the value used in the Execute is the same one that was assigned higher up the method.
How big an issue this is, obviously depends on your application, if the code's in a library etc...

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.

How to find which resource cultures are available in a ResourceManager?

I have a situation where I would like to present a list of the "available languages" for my application (which, incidentally, is an ASP .NET MVC 3 application if that makes any odds). I thought that I could automatically get this list somehow since it should just be the resx files that are included in the build (I don't need to support English UK, German Austria or anything, just English or German) and I came up with a scheme that I will present below (implemented as a singleton since it is a bit of an intensive approach).
The problem is that on some machines it returns "Arabic" even though I have no such resource and on mine (since I installed VS 2012) it returns all of them (this makes more sense to me than returning just the two real cultures plus Arabic but it seems that the ResourceManager just wasn't designed to let me get at this information so I probably should not complain). Here is the scheme...
(I have a Strings.resx and a Strings.de.resx file)
IEnumerable<CultureInfo> cultures =
CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.Where(c =>
{
// Exclude the invariant culture and then load up
// an arbitrary string so the resource manager
// loads a resource set, then get the set for the
// current culture specifically and it is, sometimes
// (I thought always but I was wrong) null if no
// set exists
if (c.LCID == CultureInfo.InvariantCulture.LCID)
return false;
var rm = Strings.ResourceManager;
rm.GetString("HELLO", c);
return rm.GetResourceSet(c, false, false) != null;
});
So then I thought, well, I could do this based on whether the language-specific directory exists like so:
var neutralCulture = new[]
{
CultureInfo
.CreateSpecificCulture(((NeutralResourcesLanguageAttribute)
Assembly
.GetExecutingAssembly()
.GetCustomAttributes(
typeof (NeutralResourcesLanguageAttribute),
false)[0])
.CultureName)
};
IEnumerable<CultureInfo> cultures =
CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.Where(c => Directory.Exists(c.TwoLetterISOLanguageName))
.Union(neutralCulture);
This "works" (in so much as it returns English and German) but I think it is not a very stable approach being as it is prone to random problems like someone creating a folder and throwing it all out of whack. I can probably alleviate these issues with some more judicious checks (the where clause is crying out for more sophistication) but and here is the question (finally)...
Right now I am thinking of just going with a config file and keeping it totally simple since I do not really like where I have got to but is there a better way to do this (or: can it be done automatically in a safe way)?
I like your second approach for automatic detection. I would add though that you should only do this once (on application start or as part of a static constructor) and make it static instead of computing it every time you request the supported culture info.
I think the config approach would work as well, though it's not really automatic. My only thought for that case is that if you are localizing for a language, it's not something that's going to sneak into your application under the radar. That being said, adding a config value at that point seems like an easy thing to do (or to forget to do).
I'm not aware of anything built into the .NET Framework to give you this information with a method call.
I found no valid and reliable way of doing this.
In each of my assemblies I write a code like this that references the supported cultures. That's all we can do. You have to remember to update this array when you add a localization.
internal static class ThisAssembly
{
static readonly string[] SupportedCultures = new string[] { "en-US", "de-DE", };
}
I also tried to:
enumerate the loaded sattelite assemblies: there is no method for that;
get the value of ResourceManager._resourceSets: the dictionary of loaded sets gives correct and invalid values.
But to no avail.

Compile Time Reflection in C#

I frequently write C# code that has to use magic strings to express property names. Everyone knows the problems with magic strings. They are very difficult to refactor, they have no compile time checking, and often they lead to hard-to-diagnose issues. Yet C#/.NET uses them all over the place to represent property/class/method names.
This issue has persisted for years and years, and the only viable solution currently is to use an expression tree which is then parsed at run-time for the property name. This gets you satisfactory compile-time checking, but it complicates the code (requiring parameters of type Expression), and it incurs a run-time cost.
Does anyone know if there has ever been a feature consideration for C#/.NET to add compile-time reflection to overcome this pervasive problem?
It seems like it would be an easy addition to make, it would be a non-breaking change, and it would greatly benefit many developers. The typeof() operator already performs a form of compile-time reflection, so it seems like an operator nameof() (or something similar) would be very complimentary.
In addition, does anyone know of any potential issues with such a feature?
Thanks for the help.
Straight from the source - this is a blog post by a C# language designer, and the "User" in this post asks about the same questions as you and is answered. The author says there would be a need to specify a syntax for every metadata item you'd want to ask for and it's not trivial - ie. which overload you want, if you want "info-of" method and the method is overloaded? What if there are generics and explicit interface implementations involved? And so on. It turns out, while it wasn't deemed worthy of implementation in 2009 because of those reasons, we will get it in C# 6 in 2015 - see C# Language Design Notes for Jul 9, 2014 .
In C# 6.0, a new operator, nameof, is being added that will allow you to get the names of properties, classes, fields, events, and variables at compile time.
Link to the design notes
No more reflection for information the compiler already knows at design time!
I was having a similar problem. Only recently discovered that .NET Framework 4.5
has a feature called the Caller Info attributes. By using these, you can obtain information about the caller to a method at compile time. You can obtain file path of the source code, the line number in the source code, and the member name of the caller.
public void DoProcessing()
{
TraceMessage("Something happened.");
}
public void TraceMessage(string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Trace.WriteLine("message: " + message);
Trace.WriteLine("member name: " + memberName);
Trace.WriteLine("source file path: " + sourceFilePath);
Trace.WriteLine("source line number: " + sourceLineNumber);
}
Yet C#/.NET uses them all over the place to represent property/class/method names.
First off: I disagree. There are certain frameworks (WebForms, e.g.) that use magic strings all over the place, but the base libraries for C# and .NET tend to avoid such things remarkably well.
Secondly: In many instances where magic strings are used, ReSharper is able to recognize errors. This can help quite a bit.
Finally: What you're asking for may be possible via the Roslyn Compiler, which promises to provide "Compiling as a service."

Categories

Resources