Question

A couple of readonly variables will be used. Almost all of the classes will be using those variables. Either I place all of the variables in a separate internal static class or I pass them on repeatedly in all the classes' constructor parameters. What would be the better of the 2? Performance-wise only please.

Was it helpful?

Solution

Either I place all of the variables in a separate internal static class or I pass them on repeatedly in all the classes' constructor parameters.  What would be the better of the 2? Performance-wise only please.

As the commenters have noted there is going to be mostly negligible difference from a speed performance perspective.

The only way you're going to find a meaningful difference is if you have data sets (instance object counts) that are extremely large — as there you may notice a space usage difference, which at extreme scale will result in a speed difference as well.

However, this assumes some details that I'm inferring from your question, and these assumptions may not hold..

What I'm getting at is that the "static class with static members" approach uses tight coupling of the code in some classes to the static data in the other class.  Of course, this approach will not allow different instances to have different contexts, but then we're not taking maintenance and/or usability merits, just performance.  As a result this will save on some instance data over some of other approaches.

In the "pass them on repeatedly ... classes' constructor parameters" approach, I'm now assuming that the constructors store/forward these formal parameters into instance variable in their respective classes — and these instances then represent larger instances than we would have with the more tightly coupled approach.

Yet still, instead of providing multiple parameters over and over, we could provide a single (shareable) context object holding multiple values as constructor parameter to be stored in the instances.  While this represents fewer parameters to pass and then store, it is now a reference, which is 64-bits on a 64-bit architecture (where as two 32-bit ints or several booleans would have been no larger).  So, this is a space win only if the number and size of the parameters is larger than pointer size.

If on the other hand, your constructors are computing with these parameters and are not storing them in the instance for the instance object's later (methods to) use, then there is no space penalty, and thus we're back to negligible performance differences.

In short, if there is a space cost to one approach over another, it can show up when there are very high volumes of instances, and usually the more space used, then, the slower the code due to cache efficiency issues (with other things being equal, like the overall algorithm).

OTHER TIPS

Performance-wise only please.

You have already made the wrong decision, right there. This is called "premature optimisation" and it's frowned upon, for good reasons.

The correct question to be asking is what effect will the two approaches have on the ease of reading, testing, reasoning and maintaining the code. And the answer to that comes down to just how immutable are these "variables". How are they set? What do you mean by they are read-only? Are they completely immutable, or simply read-only from an external perspective, but can change internally?

It's all about trade-offs. Having global immutable values can improve the readability of your code and reduce the amount of parameter passing you have to do. But it increases coupling and can make testing more difficult. And if they can change in any way, then they are a huge evil global variable anti-pattern and you should run screaming from even considering them.

Do both, using IoC

You should do both, using an Inversion of Control container, which along with the LSP will provide clean separation of concerns and greatly ease automated unit testing.

The idea is that you define a "static" (not really) class and inject it into the constructor everywhere it is needed. The container deals with the instancing for you, and you can set your settings to be "singleton" or "single instance," which essentially makes it like a static class, only you can stub and mock its interface. You wouldn't be able to do that with a normal static class.

In this example I'll use a common IoC container known as Autofac (which is free, and available on NuGet. There are many others too.) First we define an interface that exposes the settings we need:

public interface ISettings
{
    string Setting1 { get; }
    string Setting2 { get; }
}

Then we define a concrete implementation.

public class GlobalSettings : ISettings
{
    //These are just examples. In production code, perhaps they are database calls.
    public string Setting1 { get { return "Foo"; } }
    public string Setting2 { get { return "Bar"; } }
}

We then add our settings to the composition root, along with our application:

public static IContainer CompositionRoot()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<GlobalSettings>().As<ISettings>().SingleInstance();
    builder.RegisterType<Application>();
    return builder.Build();
}

Oh by the way here's the application. This one is just a dummy example:

public class Application
{
    private readonly ISettings _settings;

    public Application(ISettings settings)  //Injected automatically
    {
        _settings = settings;
    }

    public void Run()
    {
        Console.WriteLine("Setting1 = '{0}'", _settings.Setting1);
        Console.WriteLine("Setting2 = '{0}'", _settings.Setting2);
    }
}

Now to execute it, we call the composition root to compose the object graph, ask Autofac to give us an Application, and call Run(). The container will inject the settings automatically, and it will always inject the same instance. It's very easy. Ends up being one line of code:

public static void Main()
{
    CompositionRoot().Resolve<Application>().Run();
}

And here's the output from Application:

Setting1 = 'Foo'
Setting2 = 'Bar'

Here is a full working example on DotNetFiddle.

The above is a very common pattern and I highly recommend you learn it. Also, it will definitely satisfy your OCD tendencies, as it keeps everything very organized.

Performance

The means by which you supply variables where they are needed are not likely to move the needle with regards to performance. However, structuring the code in this manner will do two things to help you with performance:

  1. By having well structured code that is simpler to maintain, your development team will have more time to focus on performance-related matters.

  2. The ability to substitute mocks and stubs means you can isolate pieces of code and test them independently, which may help you determine where performance problems come from. For example, if you isolate away the database client and things speed up, it's likely that data access is the bottleneck.

For example, let's say we discover that our application is running terribly slow and we suspect that the data retrieval logic in our GlobalSettings class is causing the problem. We can easily create a mockup:

public class MockSettings : ISettings
{
    //Dummy implementation without database calls
}

and register it instead of the GlobalSettings:

builder.RegisterType<MockSettings>().As<ISettings>().SingleInstance();

And now when we run the application, the database calls don't happen, and we can tell what portion of the performance problem is isolated away, and what remains.

Licensed under: CC-BY-SA with attribution
scroll top