Reserved max value in the .NET assembly version - c#

I wonder why the assembly version can not have the max UInt16 values. The MSDN states that:
All components of the version must be integers greater than or equal
to zero. Metadata restricts the major, minor, build, and revision
components for an assembly to a maximum value of UInt16.MaxValue - 1.
Does anyone know what the max value is reserved for?
UPDATE 1
It's not a duplicate question. I'm not asking about the max value of UInt16 itself, that is 65535. I'm asking why the max possible value for version is 65534. I haven't found any explanation about internal usage of the last value and why it is reserved in .NET.
UPDATE 2
People say that max value could be used for *. Yes, it is really possible to set the assembly version to something like 1.0.*. And I did it. And then checked the manifest of the compiled file:
And as you can see, compiler didn't set build and revision to 65535. Instead, it has generated some specific values. So, probably max value is not for *.

Why are build numbers limited to 65534?
FILEVERSION
Binary version number for the file. The version consists of two 32-bit integers, defined by four 16-bit integers. For example, "FILEVERSION 3,10,0,61" is translated into two doublewords: 0x0003000a and 0x0000003d, in that order. Therefore, if version is defined by the DWORD values dw1 and dw2, they need to appear in the FILEVERSION statement as follows: HIWORD(dw1), LOWORD(dw1), HIWORD(dw2), LOWORD(dw2).
Metadata restricts major, minor, build, and revision to a maximum of UInt16.MaxValue - 1. ref

Related

Can Random.Next() ever return int.MaxValue?

The documentation for the Random.Next() method states that it returns:
A 32-bit signed integer that is greater than or equal to 0 and less than MaxValue.
But, I took a peek at the implementation, and while I don't understand the algorithm (a quick Google search suggests that it is a subtractive generator), I can't see any way in which a value of exactly int.MaxValue is ruled out.
If, for pedantic reasons, someone wants a random number across the entire range of 32-bit integers, does Random.Next() alone suffice, or does it become necessary to do something like assemble two separate 16-bit samples?
It will always be less than int.MaxValue.
In your linked source code it explicitly handles int.MaxValue:
if (retVal == MBIG) retVal--;
MBIG is defined earlier:
private const int MBIG = int.MaxValue;
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Random.cs#L105

Which data type should I use to handle nine-digit account numbers and why?

Which data type should I use to handle 9-digit account numbers and why?
varchar(9) or int or decimal or something else ?
I'm talking from a database perspective — and the DBMS is Informix.
TL;DR Use CHAR(9).
You have a number of options, most of them mentioned in the comments. The options have different trade-offs. They include:
CHAR(9). This uses 9 bytes of storage, but can store leading zeros and that can save on formatting in the applications. You can write a check constraint that ensures that the value always contains 9 digits. If you later need to use longer numbers, you can extend the type easily to CHAR(13) or CHAR(16) or whatever.
INTEGER. This uses 4 bytes of storage. If you need leading zeros, you will have to format them yourself. If you later need more digits, you will need to change the type to BIGINT.
SERIAL. This could be used on one table and would automatically generate new values when you insert a zero into the column. Cross-referencing tables would use the INTEGER type.
DECIMAL(9,0). This uses 5 bytes of storage, and does not store leading zeros so you will have to format them yourself. If you later need more digits, you can change the type to DECIMAL(13,0) or DECIMAL(16,0) or whatever.
BIGINT and BIGSERIAL. These are 8-byte integers that can take you to 16 digits without problem. You have to provide leading zeros yourself.
INT8 and SERIAL8 — do not use these types.
VARCHAR(9). Not really appropriate since the length is not variable. It would require 10 bytes on disk where 9 is sufficient.
LVARCHAR(9). This is even less appropriate than VARCHAR(9).
NCHAR(9). This could be used as essentially equivalent to CHAR(9), but if you're only going to store digits, you may as well use CHAR(9).
NVARCHAR(9). Not appropriate for the same reasons that VARCHAR(9) and NCHAR(9) are not appropriate.
MONEY(9,0). Basically equivalent to DECIMAL(9,0) but might attract currency symbols — it would be better to use DECIMAL(9,0).
Any other type is rather quickly inappropriate, unless you design an extended type that uses INTEGER for storage but provides a conversion function to CHAR(9) that adds the leading zeros.

I want to store large chunk data in true/false format using bits

Consider example where I have many types(types - some sections). For each type there are multiple values and out of available values possible useful values are less.
each type will store 30 values. All 30 values are not applicatble but I need to store in 1/0 format. Consuming byte is also costly here.
Please guide me on the same.
Consider using BitArray class.
You can define either an int column (If you have value less than or equal to 32) or bigint column (long in case C#) (If you have value less than or equal to 64) along with each Type and then define each bit of either int or bigint (long in case C#) column as one value of type and then store.
For Example: Suppose that each type has four value Physics, Maths, Chemistry, English and others up to 32. Now we have a type as "Class" which have only three value Physics, Maths and English and rest is not available. So value will be 0000000000000000000000000001011 = 13.

How do you deal with numbers larger than UInt64 (C#)

In C#, how can one store and calculate with numbers that significantly exceed UInt64's max value (18,446,744,073,709,551,615)?
Can you use the .NET 4.0 beta? If so, you can use BigInteger.
Otherwise, if you're sticking within 28 digits, you can use decimal - but be aware that obviously that's going to perform decimal arithmetic, so you may need to round at various places to compensate.
By using a BigInteger class; there's one in the the J# libraries (definitely accessible from C#), another in F# (need to test this one), and there are freestanding implementations such as this one in pure C#.
What is it that you wish to use these numbers for? If you are doing calculations with really big numbers, do you still need the accuracy down to the last digit?
If not, you should consider using floating point values instead. They can be huge, the max value for the double type is 1.79769313486231570E+308, (in case you are not used to scientific notation it means 1.79769313486231570 multiplied by 10000000...0000 - 308 zeros).
That should be large enough for most applications
BigInteger represents an arbitrarily large signed integer.
using System.Numerics;
var a = BigInteger.Parse("91389681247993671255432112000000");
var b = new BigInteger(1790322312);
var c = a * b;
Decimal has greater range.
There is support for bigInteger in .NET 4.0 but that is still not out of beta.
There are several libraries for computing with big integers, most of the cryptography libraries also offer a class for that. See this for a free library.
Also, do check that you truly need a variable with greater capacity than Int64 and aren't falling foul of C#'s integer arithmetic.
For example, this code will yield an overflow error:
Int64 myAnswer = 20000*1024*1024;
At first glance that might seem to be because the result is too large for an Int64 variable, but actually it's because each of the numbers on the right side of the formula are implicitly typed as Int32 so the temporary memory space reserved for the result of the calculation will be Int32 size, and that's what causes the overflow.
The result will actually easily fit into an Int64, it just needs one of the values on the right to be cast to Int64:
Int64 myAnswer = (Int64)20000*1024*1024;
This is discussed in more detail in this answer.
(I appreciate this doesn't apply in the OP's case, but it was just this sort of issue that brought me here!)
You can use decimal. It is greater than Int64.
It has 28-29 significant digits.

.NET: Large revision numbers in AssemblyVersionAttribute

We have the convention of versioning our builds as [major].[minor].[micro].[revision], e.g. 2.1.2.33546.
Our build-script automatically updates an AssemblyInfo.cs file containing
[assembly: AssemblyVersion("x.y.z.w")]
in order to embed the version-number in the assembly.
But our Subversion-repository just reached revision #65535, which broke our build.
It turns out that each number in the version-number has a maximum value of 65534 (probably due to a Windows-restriction).
Have you encountered this problem? Any good solutions/workarounds?
We like the scheme of embedding the revision-number and we obviously can't just reset our Subversion-server :-)
A bit more Background information:
Why are build numbers limited to 65535?
As this is unlikely to get changed, your options are:
Take the Revision Modulo 65535, which means you are back to 1
Use the Micro-Field in your version number to split the version number by dividing the revision by 1000. That means your version could be 1.0.65.535
Do not store the SVN Revision in the AssemblyVersion, but instead in the AssemblyInformationalVersion. That way your Application can still access it for display purposes, although you can't use Windows Explorer anymore to quickly check the SVN Revision
Do not store the SVN Revision in the AssemblyVersion, but instead in the AssemblyProduct or AssemblyDescription fields. Again, that way your Application can still access it, but also Explorer will now show it in the Property Sheet.
One option might be to just use the [AssemblyFileVersion]; this still raises a warning, but it'll build, at least:
[assembly: AssemblyFileVersion("1.0.0.80000")]
We decided to use the same convention, and due to the limitations of Windows version numbers we chose to drop the "micro" part of our version numbers in order to preserve the revision number. Our version numbers are now [major].[minor].[revision / 10000].[revision % 10000], so the assemblies built from revision 65535 have the version 2.01.6.5535.
According to MSDN, the components of the AssemblyVersionAttribute version number are limited to UInt16.MaxValue - 1 by the assembly meta data, i.e. you can't store larger numbers in an assembly file. The file version, as Marc Gravell suggests, might be enough for you, depending on who will read your version number.
This answer is for people, who use the Azure Build Pipeline, want to insert the BuildId value as last number of the assembly version and have a problem with a too large value of the BuildId. (> 65535)
My solution is to use the last 4 or 5 digits of the BuildId, which are injected into the file AssemblyInfo.cs.
I don't use the modulo operation, because than the version number would look totally different from the BuildId (after reaching the limit). Instead in my solution the "shorted" version looks similar to the BuildId.
Examples:
The AssemblyVersion is 1.0.0.0 and the BuildId is 333. --> The new AssemblyVersion becomes 1.0.0.333. (Small number, no problem.)
The AssemblyVersion is 1.0.0.0 and the BuildId is 55555. --> The new AssemblyVersion becomes 1.0.0.55555. (Still in range.)
The AssemblyVersion is 1.0.0.0 and the BuildId is 66666. --> The new AssemblyVersion becomes 1.0.0.6666. (Uses last 4 digits. More isn't possible.)
The AssemblyVersion is 1.0.0.0 and the BuildId is 111111. --> The new AssemblyVersion becomes 1.0.0.11111. (Uses last 5 digits.)
Easy usage by following steps
Step 1: Define the variable shortBuildId in your pipeline by this snippet.
variables:
- name: shortBuildId # note: The last 4 or 5 digits of the BuildId, because for the assembly version number the maximum value is 65535
value: '[not set]' # will be set by powershell script
Alternatively you could define it like this. It depends on the style how you did define your already existing variables.
variables:
shortBuildId: '[not set]'
Step 2: Insert these tasks above the existing tasks.
The first task creates the short BuildId and saves it to variable shortBuildId.
The second task updates the 4th version field in the file AssemblyInfo.cs. So the short buildId is injected into both, the AssemblyVersion and the AssemblyFileVersion.
Note: In this file you need an assembly version with 4 numbers (e.g. 1.0.0.0). If you have only 3 numbers (e.g. 1.0.0) it will not work.
- task: PowerShell#2
displayName: Define short build ID
# If allowed, use the last 5 digits. If they are larger than 65000, use the last 4 digits. Leading zeros are removed.
# This is needed, because the full build ID can't be used as number for the assembly version.
inputs:
targetType: 'inline'
script: |
$shortId = $env:BUILD_BUILDID
$shortId = $shortId % 100000
if ($shortId -gt 65000) { $shortId = $shortId % 10000 }
Write-Host "Build ID: $env:BUILD_BUILDID --> $shortId"
Write-Host "##vso[task.setvariable variable=shortBuildId]$shortId"
showWarnings: true
- task: RegexReplace#3
displayName: Insert shortBuildId into AssemblyInfo:
InputSearchPattern: 'myProjectDirectory\Properties\AssemblyInfo.cs'
FindRegex: '(\[assembly: (AssemblyVersion|AssemblyFileVersion)\("\d+\.\d+\.[0-9*]+)\.[0-9*]+("\)\])'
ReplaceRegex: '$1.$(shortBuildId)$3'
UseUTF8: true
UseRAW: true
Step 3: Adjust the path in the second task related to your project.
Edit the value of InputSearchPattern.
If you want to insert the shortBuildId into all projects of your solution, just write InputSearchPattern: '**\AssemblyInfo.cs'
Credit
Thanks to Dr. Edmund Weitz for his great tool The Regex Coach, which is free to use.
I'd like to propose by way of answer the following scheme for anyone using semver/gitflow:
AssemblyVersionAttribute
SemVer/Gitflow
Major Version
Major
Minor Version
Minor
Build Number
Patch
Revision
Gitflow ID
Where "Gitflow ID" is a digit followed by 0000 - 9999, per the following:
Gitflow ID
Branch
00000 - 09999
Release (alpha)
10000 - 19999
Release (beta)
20000 - 29999
Release (RC)
30000 - 65535
Development
The intuition behind 00000 - 29999 is that these numbers represent something of a logical negative pre-release number, 30000 represents logical zero, and 30001 - 65535 represent logical positive. More formally, this is a kind of 10's complement representation, with offset K = 30000.
So for example:
Topic branch feature/A starts at 0.0.0.30000
Simultaneously, topic branch feature/B also starts at 0.0.0.30000
feature/B merges to dev at 0.0.0.31000 while feature/A is at 0.0.0.30021
feature/A merges updates from dev at 0.0.0.31001
feature/A merges to dev at 0.0.0.32000
v1.0-alpha.1 release starts from dev at 1.0.0.00001
v1.0-rc.3 at 1.0.0.20002
Finally v1.0 released to Master at 1.0.0.30000
Hotfix v1.0.1 applied at 1.0.1.30000
Meanwhile v1.1 development continuing at 1.0.1.30002
The above suggests that the development range 30000-65535 could be further subdivided for topic branches, i.e. DDTTT, with DD ranging from 30 to 65 (max 65 - 30 + 1 = 36 dev PRs until release). Alternatively, the whole range could be used for development and topic branches without distinction; in this case, merging from dev to topic would have topic be dev + 1 and vice-versa. Either case allows there to be multiple identical version numbers at the topic branch level, but only a single version number for any dev commit. The DDTTT arrangement makes it clearer which version number represents a dev commit (e.g. 57000) at the expense of limiting the number of dev commits in a release. However, assuming a frequent enough release cadence, this should not be a problem. At any rate, production releases are clearly seen as having gitflow IDs of 30000.

Categories