Get a instance of an type without calling constructors but still initialize fields/properties;

404 views Asked by At

Basically what I want lies somewhere between FormatterServices.GetUninitializedObject() and Activator.CreateInstance().

This is for a plugin type of system so the type is variable, but I dont imagine that is an issue as both the above handle variable types just fine.

Basically I want to create an instance of the plugin's class, initialize all the fields and properties with their defined values but hold off on calling the constructor until my parent application sees if it has any configured settings it wants to inject in.

IInputDeviceEnumerator newEnum = (IInputDeviceEnumerator)FormatterServices.GetUninitializedObject(type);

if (newEnum is IIMConfigurable typeSettings)
{

    string pluginDirectory = Path.GetDirectoryName(new System.Uri(typeSettings.GetType().Assembly.CodeBase).AbsolutePath);
    string pluginConfigPath = Path.Combine(pluginDirectory, "settings.json");

    if (File.Exists(pluginConfigPath))
    {
        try
        {
            JsonConvert.PopulateObject(File.ReadAllText(pluginConfigPath), typeSettings.config);
        }
        catch { }
    }

    SharedProperties.Settings.pluginSettings.settingsGroups.Add(typeSettings.config);
}
var constructor = type.GetConstructor(Type.EmptyTypes);
constructor.Invoke(newEnum, null);

I have a feeling the answer lies somewhere in PopulateObjectMembers, but I have not found enough info on it yet to decide.

2

There are 2 answers

4
Eugene Podskal On

As far as I know there are no analogues to C++'s placement new that combined with FormatterServices.GetUninitializedObject would have probably solved your problem.

But I believe that you are trying to do is a step in a wrong direction - trying to fight constructor invariants/work on uninitialized objects is usually a bad idea.

Unless this is some already active and (relatively) widely used plugin system and you have no other choice, I'd recommend you to redesign it using one of the more standard and language/platform-independent approaches:

  1. Either pass all parameters to the constructor as some Dictionary/dynamic.
  2. Or do the same with some IPluginFactory.Create.
  3. Or have an Initialize method that accepts the same Dictionary/dynamic and initializes the plugin after it had been constructed.

Personally, I would have gone with constructor accepting Dictionary/dynamic.

0
Wobbles On

I appreciate the the help and guidance on this one, but for my final solution, I decided to think a bit outside the box.

Since this was for a plugin system that had both internally configurable and externally overridable settings I wanted to settings to be accessible even if the plugin was not full initialized.

My solution was to create an attribute on the plugin type that was a pointer to another type that housed the settings. Like I said, outside the box.

This allowed me to see the attribute and defined settings class, create an instance of the settings class and populate it all before I had begun initializing the plugin. (this also had the benefit of being able to modify plugin settings without the plugin being enabled at all)

then in my plugin wrapper in the instance creation code, I detected if there is a constructor on the plugin that accepts the same type back and uses that otherwise it uses the default.