Используйте Activator.CreateInstance () и поддерживайте несколько подписей конструктора - PullRequest
0 голосов
/ 03 марта 2020

Мне нужно создать экземпляр типа, который ДОЛЖЕН иметь параметр IConfiguration, но МОЖЕТ иметь другие параметры.

В настоящее время я использую следующий код:

Activator.CreateInstance(myType, BindingFlags.CreateInstance, null, new object[] { configuration }, CultureInfo.InvariantCulture);

myType - это тип для создания экземпляра. Написанный так, он требует конструктора, который имеет ровно один параметр типа IConfiguration. Как видите, я передаю объект configuration через массив объектов, чтобы удовлетворить это требование.

Теперь есть новое требование: конструктор myType может иметь несколько параметров. Один из них должен принять объект IConfiguration. Другие параметры могут быть проигнорированы (или установлены по умолчанию) в этой части кода. Как мне этого добиться?

Редактировать:

Это возможные типы для myType. V1 - текущее требование, V2 - новое требование. Все три варианта действительны и должны быть созданы с помощью объекта configuration.

public class PluginV1
{
    private readonly IConfiguration configuration;

    public PluginV1(IConfiguration configuration)
    {
        this.configuration = configuration;
    }
}

public class PluginV2_A
{
    private readonly IConfiguration configuration;
    private readonly IExampleService exampleService;

    public PluginV2_A(IConfiguration configuration, IExampleService exampleService)
    {
        this.configuration = configuration;
        this.exampleService = exampleService;
    }
}

public class PluginV2_B
{
    private readonly IConfiguration configuration;
    private readonly IEnvironment environment;

    public PluginV2_B(IConfiguration configuration, IEnvironment environment)
    {
        this.configuration = configuration;
        this.environment = environment;
    }
}

1 Ответ

1 голос
/ 03 марта 2020

Может быть, я что-то упустил, но вы можете использовать простое отражение, чтобы получить правильный конструктор, если их более одного, и изучить его входные параметры.

    public class Config : IConfiguration{}

    static void Main(string[] args)
    {
        var config = new Config();

        var o1  = Instantiate(typeof(PluginV1), config);
        var o2  = Instantiate(typeof(PluginV2_A), config);
        var o3  = Instantiate(typeof(PluginV2_B), config);
        Console.WriteLine(o1);
        Console.WriteLine(o2);
        Console.WriteLine(o3);
        Console.ReadKey();
    }

    private static object? Instantiate(Type type, IConfiguration config)
    {
        var targetConstructor =  type.GetConstructors().First();
        // in case there are several .ctors we can find suitable
        //        .First(info => info.GetParameters().Any(parameterInfo =>
        //            typeof(IConfiguration).IsAssignableFrom(parameterInfo.ParameterType)));
        var parameters = targetConstructor.GetParameters().Select(info =>
        {
            if (!typeof(IConfiguration).IsAssignableFrom(info.ParameterType))
            {
                return GetDefault(info.ParameterType);
            }

            return config;
        }).ToArray();
        var instance = Activator.CreateInstance(type, parameters);
        return instance;
    }

    // getting default values https://stackoverflow.com/a/353073/517446
    public static object GetDefault(Type type)
    {
        if(type.IsValueType)
        {
            return Activator.CreateInstance(type);
        }
        return null;
    }
...