Is it good practice to do initialization inside an Property?
I have a PluginProvider class that uses the PluginLoader component to load plugins (managed / native) from the file system. Inside the PluginProvider class, there is currently a property called "PluginTypes" that calls the instance method "InitializePlugins" in get ().
class PluginProvider
{
IEnumerable<IPluginType> PluginTypes
{
get
{
//isInitialized is set inside InitializePlugins method
if(!isInitialized)
{
InitializePlugins(); //contains thread safe code
}
//_pluginTypes is set within InitializePlugins method
return _pluginTypes;
}
}
}
I am considering refactoring this piece of code. I want to know if this initialization inside a property is appropriate. I know that heavy operations should not be done on property. But when I checked this link: http://msdn.microsoft.com/en-us/library/vstudio/ms229054.aspx , found this "Specifically, operations that access the network or filesystem (except once for initialization) will most likely be methods, not properties. " Now I am a little confused. Please, help.
source to share
This is, of course, a matter of taste. But what I would do depends on the duration of the operation you are trying to perform. If it takes time to load plugins, I would create a public method that any user would need to call before working with the class. Another approach is to put the method inside a constructor, but IMO constructors should return as quickly as possible and should contain the field / property initialization.
class PluginProvider
{
private bool _isInitialized;
IEnumerable<IPluginType> PluginTypes { get; set;}
public void Initialize()
{
if (_isInitialized)
{
return;
}
InitializePlugins();
_isInitialized = true;
}
}
Note the downside of this that you will need to make sure the Initialize method has been called before consuming any operation.
Another thing that just came to mind while supporting this approach is exception handling. I'm sure you wouldn't want your constructorcto to pick any type IOException
if it couldn't load the types from the filesystem.
source to share
- If you want to defer initialization as long as you can and don't know when your property (or properties) will be called, then what you are doing is fine.
- If you want to defer and have control over when your property is first called, you can make your method
InitializePlugins()
public and call it explicitly before accessing that property. This parameter also opens up the ability to initialize asynchronously. For example, you might haveInitializePluginsAsync()
one that returnsTask
. - If initialization latency is not a big problem, just do the initialization inside the constructor.
source to share
What you are doing there is called lazy initialization. You postpone a potentially costly operation until it exits.
Now this is not an absolute rule. If your method InitializePlugins
is taking a long time and it might affect the user interface, you might want to consider moving it into a public method, or even making it asynchronous and calling it outside of a property: when your application starts, or when you find a good moment to call a long running operation.
Otherwise, if it is a short one-time item, it may stay there. As I said, not an absolute rule. Typically, these are some guidelines that apply to a particular case.
source to share