使用 Activator.CreateInstance() 并支持多个构造函数签名
Use Activator.CreateInstance() and support multiple constructor signatures
我需要实例化一个类型,该类型必须有一个 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;
}
}
也许我遗漏了什么,但您可以使用简单的反射来获得正确的构造函数,以防有多个构造函数,并探索其输入参数。
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
public static object GetDefault(Type type)
{
if(type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
我需要实例化一个类型,该类型必须有一个 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;
}
}
也许我遗漏了什么,但您可以使用简单的反射来获得正确的构造函数,以防有多个构造函数,并探索其输入参数。
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
public static object GetDefault(Type type)
{
if(type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}