Implementation Problem with Static Sealed Class - c#

I have a Sealed class in C#, which already exists and all methods are static.
It does some file operations with xml file. The file name till today was hardcoded into source.
Now the requirement needs to keep it in Configuration file.
The problem is:
Since class is extract, i need to expose some static 'Initialize' method to assign filename to some local static filename variable, which will replace hardcoded string.
So, i always have to make sure, Initialize is called first and then later method.
So, the better way is to have constructor, which i cant write.
I want a better way to do this ensuring type safety.

If the filename field is static, you could make it a property or method and make sure the getter does the work of initializing it from the configuration file if it is not already initialized...
That way you don't have to explicitly initialize the class via a method you can have the access to the property itself initialize the value.
Something like below..
static string FileName { get { return (_field ?? _field = GetFileName()); } }
static string GetFileName() { /* TODO: Return filename from config */ }

Why can't you use a static constructor?
You could write a static constructor to initialize your paths before the static members are referenced.
More info can be found here

If the class itself doesn't know how to access the config I'd use a one time setter:
private static string _filename;
public static string Filename
{
get
{
if(_filename==null)
throw new InvalidOperationException("Filename not set");
return _filename;
}
set
{
if(_filename!=null)
throw new InvalidOperationException("Filename set twice");
_filename=value;
}
}
Or if the class can access the config directly it's even easier:
private static readonly string Filename;
static MyClassName()
{
Filename=GetFilenameFromConfig();
}
Just initialize it in a static constructor.

Assuming the configuration file path is known (i.e. the class takes no formal arguments), then a static constructor might help.

You could change your current class from something like:-
public static Foo
{
public static void Execute()
{
const string FileName = "foo.xml";
// ...
}
}
To something like
public static Foo
{
public static void Execute()
{
Execute("foo.xml");
}
public static void Execute(string fileName)
{
// ...
}
}
Current clients of the code can continue to use the original method (hard coded file name) and any new clients which have the file name as a configuration item can use the new method which takes the file name as a parameter. Or, if you have decided that all client should use the new method, then you can change them to do that and remove the old method.

The simplest option would be to add a static constructor. That will be executed before any other code:
public static class Foo
{
static Foo()
{
// Initialization code
}
// Other methods which can depend on initialization code having run
}
As I say, this is the simplest - in terms of changes to your existing code. However, code like this tends to be hard to debug, and if you have a lot of static constructors which depend on each other, you can get into some tricky situations (particularly if you have cyclic dependencies). For an example of this, watch the "C# Puzzlers" video from NDC 2010 - an excellent talk given by Eric Lippert and Neal Gafter.

Related

Can a static member variable be used to cache a value in a static class?

I've come across this piece of code where it looks like the original developer has tried to use a static string to cache a value in a static class.
public static class GetStringFromSomeProcess
{
private static string theAnswer;
public static string GetString
{
get
{
if(theAnswer == null)
{
theAnswer = GoGetTheAnswerFromALongRunningProcess();
}
return theAnswer;
}
}
}
As far as I can see this won't work, as you can't instantiate the GetStringFromSomeProcess class, GoGetTheAnswerFromALongRunningProcess will be called every time GetString is used. Am I missing something?
This will work fine - there is only one instance of theAnswer because it is static - and (also because it is static) it can be accessed from a public static property. This means that any changes made to it will be visible to all code that accesses it. So the first call to GetString will set theAnswer to non-null, and subsequent calls will not make a call to GetStringFromSomeProcess().
However, the solution you posted is not threadsafe because GoGetTheAnswerFromALongRunningProcess() could be called simultaneously by multiple threads.
.Net provides the Lazy class to solve this issue, as follows:
public static class GetStringFromSomeProcess
{
private static readonly Lazy<string> _theAnswer = new Lazy<string>(GoGetTheAnswerFromALongRunningProcess);
public static string GetString
{
get
{
return _theAnswer.Value;
}
}
public static string GoGetTheAnswerFromALongRunningProcess()
{
return "X";
}
}
You supply to the constructor of the Lazy<T> class a method that it can call when needed in order to create the object that it is wrapping. In the example above, I pass GoGetTheAnswerFromALongRunningProcess to its constructor.
Also note that it's usually a bad idea to have a property that can take a very long time to return. It's better to make it a method:
public static string GetString()
{
return _theAnswer.Value;
}
You are right in saying that the class can't be instantiated, but the class will exist within the application.
Therefore, only the first time the property is accessed, will the method GetStringFromSomeProcess be called. Every other time after that, the check for == null will resolve to false and the value evaluated by the first call will be returned.
Does it work correctly without creating an object of the GetStringFromSomeProces class? Since the string, theAnswer, is also static, it could potentially work, but I'm wondering when that variable will be initialized. Typically you would code it like you are suggesting with initialization of the GetStringFromSomeProcess Class.
Main.cs
...
GetStringFromSomeProcess getString = new GetStringFromSomeProcess();
string answer = getString.theAnswer();
...
GetStringFromSomeProcess.cs
public class GetStringFromSomeProcess
{
private string _theAnswer;
public string theAnswer
{
get
{
if(theAnswer == null)
{
GoGetTheAnswerFromALongRunningProcess getAnswer = new GoGetTheAnswerFromALongRunningProcess();
_theAnswer = getAnswer.GetAnswer();
}
return _theAnswer;
}
}
}

Use an anonymous method to avoid creating a single-use object?

I'm trying to refactor a method that parses through a file. To support files of arbitrary size, the method using a chunking approach with a fixed buffer.
public int Parse()
{
// Get the initial chunk of data
ReadNextChunk();
while (lengthOfDataInBuffer > 0)
{
[parse through contents of buffer]
if (buffer_is_about_to_underflow)
ReadNextChunk();
}
return result;
}
The pseudo code above is part of the only public non-static method in a class (other than the constructor). The class only exists to encapsulate the state that must be tracked while parsing through a file. Further, once this method has been called on the class, it can't/shouldn't be called again. So the usage pattern looks like this:
var obj = new MyClass(filenameToParse);
var result = obj.Parse();
// Never use 'obj' instance again after this.
This bugs me for some reason. I could make the MyClass constructor private, change Parse to a static method, and have the Parse method new up an instance of Parse scoped to the method. That would yield a usage pattern like the following:
var result = MyClass.Parse(filenameToParse);
MyClass isn't a static class though; I still have to create a local instance in the Parse method.
Since this class only has two methods; Parse and (private) ReadNextChunk, I'm wondering if it might not be cleaner to write Parse as a single static method by embedding the ReadNextChunk logic within Parse as an anonymous method. The rest of the state could be tracked as local variables instead of member variables.
Of course, I could accomplish something similar by making ReadNextChunk a static method, and then passing all of the context in, but I remember that anon methods had access to the outer scope.
Is this weird and ugly, or a reasonable approach?
This maybe suitable more to code review.
However, these are my comments about your design:
I don't think it will matter much about obj instance only used once. If you bugged with it, there are 2 ways to trick it:
Use of another method such as:
public int Parse()
{
var obj = new MyClass(filenameToParse);
return obj.Parse();
}
Make the MyClass implement IDisposable and wrap it in using statement. I don't recommend this since usually IDisposable has logic in their Dispose() method
I think it is better to make your MyClass accept parameter in Parse to Parse(string fileNameToParse). It will make MyClass as a service class, make it stateless, reusable and injectable.
Regarding impact to static class. First it add coupling between your consumer and MyClass. Sometimes if you want to test / unit test the consumer without using the MyClass parser, it will be hard / impossible to mock the MyClass into something you want.
All you need is a static parse method that creates an instance, much like what you suggest in your question
public class MyClass
{
// your existing code.... but make the members and constructor private.
public static int Parse(string filenameToParse)
{
return new MyClass(filenameToParse).Parse();
}
}
then
just use it like you suggest...
var result = MyClass.Parse(filenameToParse);
MyClass isn't a static class though; I still have to create a local
instance in the Parse method.
You don't need a static class to be able to leverage static methods. For example this works fine:
public class MyClass
{
public static string DoStuff(string input)
{
Console.WriteLine("Did stuff: " + input);
return "Did stuff";
}
}
public class Host
{
public void Main()
{
MyClass.DoStuff("something");
}
}

unit test static constructor w/ different config values

I have a class with a static constructor which I use to read the app.config values. How do I unit test the class with different configuration values. I'm thinking of running each test in different app domain so I can have static constructor executed for each test - but I have two problems here:
1. I do not know how to run each test run in separate app domain and
2. how do I change configuration settings at run time?
Can someone please help me with this? Or anyone has a better solution? Thanks.
Personally I would just stick your static constructor into a static method then execute that method in the static block.
You don't need to test .Net being able to load data from config files.
Instead, try to concentrate on testing your own logic.
Change your class so that it gets the configuration values from its constructor (or via properties), and then test it as you would with any other dependency.
Along the way you have also moved your class towards SRP.
As per the configuration loading - concentrate this logic in a separate, non-static class.
EDIT:
Separate the configuration logic into another class. something like this:
public static class ConfigurationLoader
{
static ConfigurationLoader()
{
// Dependency1 = LoadFromConfiguration();
// Dependency2 = LoadFromConfiguration();
}
public static int Dependency1 { get; private set; }
public static string Dependency2 { get; private set; }
}
Then, when you instantiate your class, inject it with the dependencies:
public class MyClass
{
private readonly int m_Dependency1;
private readonly string m_Dependency2;
public MyClass(int dependency1, string dependency2)
{
m_Dependency1 = dependency1;
m_Dependency2 = dependency2;
}
public char MethodUnderTest()
{
if (m_Dependency1 > 42)
{
return m_Dependency2[0];
}
return ' ';
}
}
public class MyClassTests
{
[Fact]
public void MethodUnderTest_dependency1is43AndDependency2isTest_ReturnsT()
{
var underTest = new MyClass(43, "Test");
var result = underTest.MethodUnderTest();
Assert.Equal('T', result);
}
}
...
var myClass = new MyClass(ConfigurationLoader.Dependency1, ConfigurationLoader.Dependency2);
You could go on and use IOC containers, but your problem of testing MyClass with different inputs is solved by this simple testable design.
If you read from (Web)ConfigurationManager.AppSettings, that is just a NameValueCollection, so you can replace your code that reads ConfigurationManager.AppSettings directly with code, that reads from any NameValueCollection.
Just move out your actual configuration parsing to a static method from the static ctor. Static ctor calls that static method and passes ConfigurationManager.AppSettings, but you can call that parser method from the test code, and verify the config parsing without actually touching a file, or messing with appdomains.
But on the long run, really inject your configuration parameters as seldary suggested. Create a configuration class, read the actual values at application start, and set up your IoC container to supply the same configuration instance to all requesters.
This makes further testing easier too, because you classes don't read from a global static configuration instance. You can just pass in a specific configuration instance for differet tests. Of course create a factory method for your tests, to construct a global configuration, so you don't have to do it manually all the time...
I had the same exact problem recently. The only difference was that the configuration value was coming from database instead of app.config. I was able to resolve it using TypeInitializer.
[Test]
public void TestConfigurationInStaticConstructor()
{
// setup configuraton to test
// ...
// init static constructor
ReaderTypeInit();
// Assert configuration effect
// ...
// reset static ctor to prevent other existing tests (that may depend on original static ctor) fail
ReaderTypeInit();
}
// helper method
private void ReaderTypeInit()
{
typeof(< your class with static ctor>).TypeInitializer.Invoke(null, new object[0]);
}

C# Static constructors design problem - need to specify parameter

I have a re-occurring design problem with certain classes which require one-off initialization with a parameter such as the name of an external resource such as a config file.
For example, I have a corelib project which provides application-wide logging, configuration and general helper methods. This object could use a static constructor to initialize itself but it need access to a config file which it can't find itself.
I can see a couple of solutions, but both of these don't seem quite right:
1) Use a constructor with a parameter. But then each object which requires corelib functionality should also know the name of the config file, so this has to be passed around the application. Also if I implemented corelib as a singleton I would also have to pass the config file as a parameter to the GetInstance method, which I believe is also not right.
2) Create a static property or method to pass through the config file or other external parameter.
I have sort of used the latter method and created a Load method which initializes an inner class which it passes through the config file in the constructor. Then this inner class is exposed through a public property MyCoreLib.
public static class CoreLib
{
private static MyCoreLib myCoreLib;
public static void Load(string configFile)
{
myCoreLib = new MyCoreLib(configFile);
}
public static MyCoreLib MyCoreLib
{
get { return myCoreLib; }
}
public class MyCoreLib
{
private string configFile;
public MyCoreLib(string configFile)
{
this.configFile = configFile;
}
public void DoSomething()
{
}
}
}
I'm still not happy though. The inner class is not initialized until you call the load method, so that needs to be considered anywhere the MyCoreLib is accessed. Also there is nothing to stop someone calling the load method again.
Any other patterns or ideas how to accomplish this?
You need a common location to store this. You could use the app.config even if this is a seperate assembly by defining a config section in the library assembly and referencing it you proceess app.config. Or you could just add a generic setting to appSettings and reference that without using strongly typed settings. If the value is user entered then you could use isolated storage.
Finally you could put it in a well known location in the registry at install time.
For code the following is encapsulted better
public interface ICoreLib
{
void SomeMethod();
}
public static class CoreLibManager
{
private static ICoreLib coreLib;
private static volatile bool initialized;
private static readonly object lockObject = new object();
public static ICoreLib CoreLib
{
get
{
Inititialize();
return coreLib;
}
}
/// <summary>
/// The inititialize.
/// </summary>
private static void Inititialize()
{
if (initialized)
{
lock (lockObject)
{
if (!initialized)
{
string configFile = // Fech from common location
coreLib = new MyCoreLib(configFile);
initialized = true;
}
}
}
}
/// <summary>
/// The my core lib.
/// </summary>
private class MyCoreLib : ICoreLib
{
public MyCoreLib(string configPath)
{
}
public void SomeMethod()
{
}
}
}
When you have global state like this that you need to initialize and it requires outside input to complete initialization (such as a config file), then you're stuck with the outside code that knows about the input having to call Load or Initialize to initialize your global state. There's no way around this.
The issue that you've correctly observed, however, is that anybody could try to use the global state before it has been properly Initialized, which is the downside to having it exposed in this way. The way you get around this is by refactoring all of the stateful parts of your global library into an instance class and passing references to that instance through your application. Because you control when it is created and initialized, you can now ensure it has valid state before you pass it along. You trade off the convenience of global state for the better insulation you're after.
You can use the .net configuration system to do this. The simplest way to do this is to use the <appsettings> element in your web.config file, or in your appname.exe.config file. Use:
ConfigurationManager.AppSettings["property_name"]
to access a property. Whether your code is running in a web context or as a windows app, the configuration system will find the config file and load the values you need.
You can also build a more complex system with type-safe config values and hierarchical data, but my needs were pretty simple, so I didn't explore this after the first headache set in :)
You could make the class a singleton, thus ensuring there's only ever one instance of it while also allowing for the constructor parameter.
There won't be much alternatives.
Either you pass stuff around (in that case I'd not pass the string around but create a concrete (non-static) CoreLib and pass that around or you do what you suggested.
Don't forget to hide the constructor for MyCoreLib. Currently it is public which is likely unintended.
OK, thanks everyone for your assistance. I've refactored the CoreLib project and broken out the config handling into a separate project. Now we have a solution-wide shared class for config management. The class can take care of itself with a user setting, which is exposed via the static property ConfigFile. This property also persists the modified file location if the user changes via some config dialog. Also the initialized flag will be reset if the config file changes.
public interface IConfig
{
void SomeMethod();
}
public static class ConfigurationManager
{
private static IConfig config;
private static volatile bool initialized;
private static readonly object lockObject = new object();
public static string ConfigFile
{
get { return Properties.Settings.Default.ConfigFile; }
set
{
if (Properties.Settings.Default.ConfigFile == value) return;
lock (lockObject)
{
Properties.Settings.Default.Save();
initialized = false;
}
}
}
public static IConfig Config
{
get
{
Inititialize();
return config;
}
}
private static void Inititialize()
{
lock (lockObject)
{
if (initialized) return;
config = new Configuration(Properties.Settings.Default.ConfigFile);
initialized = true;
}
}
}
internal class Configuration : IConfig
{
public ClientConfig(string configFile)
{
// Parse & validate config file
}
public void SomeMethod()
{
}
}
So now in the start-up we first validate the persisted ConfigFile setting, then attempt to access the Configuration instance via the manager's Config property. Any parsing exceptions can be handled here and dealt with accordingly. Then it is up to the developer to handle any exceptions for IConfig's methods.
if (!System.IO.File.Exists(ConfigurationManager.ConfigFile))
{
// Display config file locator dialog
ConfigurationManager.ConfigFile = someDialog.FileName;
}
try
{
IConfig config = ConfigurationManager.Config;
}
catch
{
// Error parsing config file
}

Regarding C# Static Readonly members

I have the following situation. There is some very common class in my application that contains a static readonly field called "BinDirectory" that holds the path to the bin directory. Other fields in this class, which are static readonly too, use this value to as a base to their value. On the current version BinDirectory is initialized to hold the directory where the code is running (i.e. Assembly.GetExecutingAssembly().CodeBase). I want to extend this class to initialize BinDirectory to hold the "TargetDir" from the installer context when it is run from my application installer. I can change BinDirectory to be simply static but I don't want to, since it will make me do lots of changes to a class that is common in my app. Can somebody suggest an elegant solution to this problem?
Make it a property with just the "get" accessor:
public static string BinDirectory
{
get { return _initialisedBinDirectory; }
}
Then in your static constructor code, initialise the private variable as you need.
EDIT
Delayed load (as per comment):
public static string BinDirectory
{
get
{
if (_initialisedBinDirectory == null)
// load the variable when needed
else
return _initialisedBinDirectory;
}
}
This way you only load the variable when you need it, and it's re-used whenever you call it again. Hopefully you don't class null as a valid value for it though.
This is what AppConfigs are for. In your AppSettings section, add a new key called BinDirectory. You can re-write your class as:
public static string BinDirectory
{
get
{
return ConfigurationManager.AppSettings["BinDirectory"];
}
}
Finally, as one of the last steps in your installation process, you can change the BinDirectory to point to any directory you want. So now this value is determined entirely by the installer context.
It sounds like you're loath to change a static readonly field to simply static because it would force you to change the initialization of all of the other static readonly fields in your class.
If that is correct, unfortunately there isn't a whole lot you can do but take the time to make the change. By allowing the BinDirectory field to be set at runtime you are fundamentally changing the initialization sequence of the fields. Your code will need to adapt.
I think the easiest way is to convert to using static readonly properties which do the calculation of the value on the fly.
For example:
public class Values {
public static string BinDir;
public static string OtherDir {
get { return Path.Combine(BinDir,#"Some\Other\Path"); }
}
}

Categories