We have a functions library and some utility variables are stored in two diferent ways depending on the app context desktop app/website
In website we use Sessions and in desktop static variables and we would like to unite and automatize the getters//setters for those variables without affecting performance too much
Example:
public static class Cons
{
public static bool webMode;
}
public static class ConsWEB
{
public static string Username
{
get{ return HttpContext.Current.Session["username"].ToString();}
set{ HttpContext.Current.Session["username"]=value;}
}
}
public static class ConsAPP
{
private static string _username;
public static string Username
{
get{ return _username;}
set{ _username=value;}
}
}
Solution 1 we thought, using IFs (seems bad for performance, take into account accessing variables lots of times, and in some cases the variables are custom classes with complex contents):
public static class Cons
{
public static bool webMode;
public static string Username
{
get{ return webMode? ConsWEB.Username : ConsAPP.Username; }
set
{
if(webMode) { ConsWEB.Username = value; }
else { ConsAPP.Username = value; }
}
}
}
Solution 2 using delegates, at the Static Class constructor associate delegated methods to each get and set depending on the case. If is webMode point to the get/set methods of ConsWEB, otherwise to the get/set methods of ConsAPP…
Is the solution 2 the best one performance-wise? Are there other methodologies for this cases?
Neither is optimal…
First, forget about performance think design first.
You should do it through an interface or similar:
Now your implementations (NOTE: you should not really be compiling for both desktop and web in the same assembly. System.Web, for example, is not available in Client Profile – which you should really use for desktop apps).
And then your environment static:
Now you have an extensible provider whose implementation you do not need to worry about.
I do personally also have an issue with wrapping
HttpContext.Current– however in most scenarios that does work fine – if you have any asynchrony going on, however, then you have to be careful.Also – as I mention in my comments – you no longer need to wrap the properties as statics in
Consnow. Indeed you gain an awful lot of testability and extensibility by changing code like this:To this:
Believe me there will be times in your code where you’ll wish “just for this call I’d like to override the UserName – but I can’t, because it’s a static property”.
Finally you now have another extensibility mechanism at your disposal that you don’t with statics : extension methods.
Say you add a common storage mechanism to the interface for strings:
So that’s a string indexer, allowing us to implement a dictionary-like functionality for unforeseen values. Assume they’ve both been implemented, with a
Dictionary<string, string>in theDefaultConsProviderand wrapping theSessionin theWebConsProvider).Now if I’m writing an additional module for your project that needs some additional string value – I can do this:
(Sorry had to update that last bit as for some reason I parameterised the key – which was pointless!)
That is – we can now start extending the range of strongly-typed settings offered by the provider via extension methods – without having to alter any of the original code.