0

In Python, I can have the equivalent of C# static members:

class MyClass:
  i = 0  # This is like a C# static member

print(MyClass.i)

gives output

0

But maybe my static member needs to be calculated somehow. I can do:

class MyClass:
  i = 0
  i += 10

print(MyClass.i)

gives output

10

In practice, I'm writing a config class which needs to read a json file from disk, validate it, and then populate some static members. The closest thing to what I want to do in Python would look like:

class GlobalConfig:
  with open('config.json', 'r') as f:
    config_dict = json.read(f)
  # Maybe do some validation here.
  i = config_dict["i"]
  a = config_dict["hello_world"]

Truth be told, I wouldn't really do this in Python, but I'm borrowing from C# in that everything needs to go in classes.

In practice in my C# code, I would have a GlobalConfig class in a Config.cs file and all my other files would have access to this.

But it seems I can't do anything other than declare/define members in the class body. How can I do the work of loading up and parsing my config file and have the result of that be accessible as static members to the rest of my program?

PS: I don't really want this to influence the answers I get in unless it has to, but FYI I am working with Unity.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Alexander Soare
  • 2,825
  • 3
  • 25
  • 53
  • you can have a static function that anyone can use. And even a static constructor, that does some global initialization so that your `Cnonfig`-class is allways fully initialized. – MakePeaceGreatAgain Oct 20 '22 at 13:54
  • Oh a static constructor. Cool. I supposed this is it then https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors – Alexander Soare Oct 20 '22 at 13:55
  • However I'd rather not go that path as it's pretty undeterministic when the static constructor is called - only that it *will* be called. You may have a private load-function that is called within all the others of not already done. – MakePeaceGreatAgain Oct 20 '22 at 13:57
  • @MakePeaceGreatAgain are you saying that with a static constructor it's possible I try to access the static members before the constructor has run? And if so, wouldn't C# just try to call the static constructor first anyway? – Alexander Soare Oct 20 '22 at 14:02
  • see https://stackoverflow.com/questions/1437352/when-is-a-static-constructor-called-in-c for when it is called. It's a bit over oiut of scope for your question. – MakePeaceGreatAgain Oct 20 '22 at 14:04
  • @MakePeaceGreatAgain Then a static constructor sounds perfect because it's called "before any static members are referenced" – Alexander Soare Oct 20 '22 at 14:05
  • 1
    Also see https://stackoverflow.com/questions/10465961/potential-pitfalls-with-static-constructors-in-c-sharp for potential pitfalls when using static constructor. – MakePeaceGreatAgain Oct 20 '22 at 14:07
  • @MakePeaceGreatAgain thanks you've been super helpful. For the time being I'll accept Dmitry's answer as it's more direct, but you've provided a lot of value! – Alexander Soare Oct 20 '22 at 14:10

2 Answers2

2

Are you looking for static constructor?

public class MyClass { 
  private static int i = 0;

  private static int j;

  private static int loadJ(int value) {...}

  // Static constructor will be called before the first MyClass call
  static MyClass() {
    // If you want to compute anything with static you can do it here
    i += 10; 
    // you can call static methods here, address static fields and properties
    j = loadJ(i);
  }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
1

An alternative to static constrcutors is some lazy-loading approach. In essence you just initialize your class when it is used in any way calling the loading-function internally:

public class MyClass 
{ 
    static int i;
    private static int loadJ() 
    {
        i = ReadValueFromJson();
    }

    public static DoSomething()
    {
        // load if not yet done
        if(!loaded) 
            loadj();
        // do the actual work
    }
}

The advantage here is that you get more fine-grained controll about if or if not initialization should happen. Imagine some constant within your config-class that allways has the exact same value regardless of any initialization. The downsie is that you need to add this boilerplate to all the members that need loading.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Not sure if this would have any influence on your answer, but I don't want `i` and `j` to be private. I want theme to be accessed from anywhere else in the program **after** the setup has been done. – Alexander Soare Oct 20 '22 at 14:01
  • 1
    @AlexanderSoare You can make it a public property. – MakePeaceGreatAgain Oct 20 '22 at 14:03
  • So is the idea then that I must call `DoSomething` in any place I want to use this? Just in case it hasn't been called already by some other thing? – Alexander Soare Oct 20 '22 at 14:03
  • @AlexanderSoare well, just within all the functions in your config-class. But I agree, that may become brittle when your config-class has dozenzs of members that all assume the class to be initialized in front. – MakePeaceGreatAgain Oct 20 '22 at 14:05
  • Hm yeah I think I'm not seeing any issues with the static constructor so it seems like the more suitable approach. – Alexander Soare Oct 20 '22 at 14:06
  • 1
    @AlexanderSoare Just wait until your static constructor throws an exception... Fun times when that happens. My advice: NEVER allow an exception to be thrown from a static constructor. – Matthew Watson Oct 20 '22 at 14:44