There is a class with messages for UI. I would like to give each message a unique number without manually writing it in the code. These numbers can then be used in tests. So far, it has been done like this:

public class UserMessage { private static int _index = 0; private UserMessage(string message) { this.Code = System.Threading.Interlocked.Increment(ref _index); this.Message = message; } public int Code { get; private set; } public string Message { get; private set; } public static class Group1 { public static readonly UserMessage msg1 = new UserMessage("msg1"); // ... } public static class Group2 { public static readonly UserMessage msg2 = new UserMessage("msg2"); // ... } } 

The problem is that the order of calling static constructors is not defined, and if the code is executed on different IIS servers, messages may receive different codes. Is it possible to guarantee the same numbering at run time?

The ultimate goal is to get the same numbering each time the code is executed.

  • 2
    Please note that you will probably need to keep the uniqueness between different versions of the software, incl. in 2 years, when half of the existing messages will be cut / split / merged and renamed, the old messages will still have to have their own numbers, and the new ones will not use the old ones. - Kromster
  • @Kromster is not, it does not matter to me. I will give one example: some messages are confirmations, for example, "this action will lead to X, do you want to continue?". When the user on the UI presses "Yes", I send to the server the message codes that he confirmed. During server checks, messages with these codes are not added to the list of what needs to be shown to the user. It is important for me that I would get the same numbers on different IIS servers. Even if they are different after each build, it will not break anything. - Zergatul

3 answers 3

If the number is not important to you, then the GUID is ideal for unique labels. Usually in C # I do it like this.

 class MyClass { Guid Id; public MyClass() { Id = Guid.NewGuid(); } public Guid UnicalId { get { return Id; } } } 
  • I need the numbers to be the same every time the code is executed. - Zergatul
  • "... I need the numbers to be the same every time the code is executed ..." - That was not in question :). IMHO, it makes sense to supplement it. - Alexander Muksimov
  • Look in the direction of the composite identifier - the uniqueness of the place is GUID, sameness when repeated - your method - Alexander Muksimov
  • Completed the question. I do not want to get attached to the details of the internal implementation GUID, there must be a more elegant solution. - Zergatul

Option 1. Do not use static constructors (inline initialization, something the same in the context of your question) for creating objects:

 private static UserMessage fmsg1; public static readonly UserMessage msg1 { get { if (fmsg1 == null) fmsg1= new UserMessage("msg1"); return fmsg1; } } 

Option 2. Use static constructors, but determine the order in which they are called:

 public static class Group1 { public static readonly UserMessage msg1 = new UserMessage("msg1");; public static void Register() {} } public static class Group2 { public static readonly UserMessage msg2 = new UserMessage("msg2"); public static void Register() {} } protected void Application_Start() { Group1.Register(); Group2.Register(); ... } 
  • @AndreyNOP Sorry, I didn’t copy a piece from there - I hadn’t finished my coffee yet, that is, I didn’t wake up to the end. - Igor
  • one
    It's not entirely clear how the order of creation in the first version is guaranteed - Andrey NOP
  • one
    In the second variant, I think, there are no guarantees that static constructors will not be executed before calling Group1.Register(); - Andrei NOP
  • Yes, in the first case, order is not guaranteed ... - Zergatul

The problem is that the order of calling static constructors is not defined.

We'll have to cram the creation of all the codes into one constructor:

 static class CodeHelper { public static List<UserMessage> UserMessages { get; } = new List<UserMessage>(); static CodeHelper() { UserMessages.Add(new UserMessage("msg1")); UserMessages.Add(new UserMessage("msg2")); } } public static class Group1 { public static readonly UserMessage msg1 = CodeHelper.UserMessages[0]; } public static class Group2 { public static readonly UserMessage msg2 = CodeHelper.UserMessages[1]; } 

Determine the type of collection yourself - maybe a dictionary will suit you more or, in general, instead of a collection, create a set of read-only properties


Another option to not use indexes or element names is to create all the elements in sequence in one method. In this case, of course, you will have to abandon readonly :

 public static void Init() { Group1.msg1 = new UserMessage("msg1"); Group2.msg2 = new UserMessage("msg2"); } public static class Group1 { public static UserMessage msg1; } public static class Group2 { public static UserMessage msg2; } 

When you initialize the application, you will need to call UserMessage.Init();

  • If you think this option is tantamount to manual numbering. It was possible to simply set the number through a parameter in the constructor, instead of the index in the collection. The probability of making a mistake is the same. - Zergatul