C# C语言中的动态构造函数#
我试图编写一个方法C# C语言中的动态构造函数#,c#,dynamic,constructor,runtime,C#,Dynamic,Constructor,Runtime,我试图编写一个方法GetDynamicConstructor,它将返回给定类的智能构造函数。它将接受字符串数组作为参数,并将它们解析为适当的类型(给定现有构造函数数据) 这里只有基本的类型,所以我可以依靠Parse来解析可能遇到的类型 如何编写GetDynamicConstructor的主体?此方法已存在于System.Activator类中: public static object CreateInstance (Type type, params object[] args); 当然,与
GetDynamicConstructor
,它将返回给定类的智能构造函数。它将接受字符串数组作为参数,并将它们解析为适当的类型(给定现有构造函数数据)
这里只有基本的类型,所以我可以依靠Parse
来解析可能遇到的类型
如何编写
GetDynamicConstructor
的主体?此方法已存在于System.Activator
类中:
public static object CreateInstance (Type type, params object[] args);
当然,与实际参数数据相对应的构造函数重载必须存在。可以使用更改参数的类型
请参阅:在docs.microsoft.com上
Activator.CreateInstance
有16种不同的重载。根据具体使用方法,有几种方法。Steve16351有一种方法,就是创建一个委托给一个在执行时进行所有反射的方法。另一种方法是在执行时生成一个类似于示例方法的委托,然后缓存该委托。区别在于前者更灵活,而后者更快。在每次执行时使用反射可以在选择构造函数之前考虑哪些转换是成功的。虽然编译委托必须在参数可用之前知道选择哪个构造函数,但它的性能特征更像是在C#中本机编写的方法。下面是使用表达式树生成委托的实现。您希望为每种类型缓存此项以获得最大性能:
using System.Linq.Expressions;
public static DynamicConstructor<T> GetDynamicConstructor<T>()
{
ConstructorInfo originalCtor = typeof(T).GetConstructors().First();
var parameter = Expression.Parameter(typeof(string[]), "args");
var parameterExpressions = new List<Expression>();
ParameterInfo[] paramsInfo = originalCtor.GetParameters();
for (int i = 0; i < paramsInfo.Length; i++)
{
Type paramType = paramsInfo[i].ParameterType;
Expression paramValue = Expression.ArrayIndex(parameter, Expression.Constant(i));
if (paramType.IsEnum)
{
var enumParse = typeof(Enum).GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Type), typeof(string) }, null);
var call = Expression.Call(null, enumParse, new[] { Expression.Constant(paramType), paramValue });
paramValue = Expression.Convert(call, paramType);
}
else if (paramType != typeof(string))
{
var parseMethod = paramType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null);
if (parseMethod == null)
{
throw new Exception($"Cannot find Parse method for type {paramType} (parameter index:{i})");
}
paramValue = Expression.Call(null, parseMethod, new[] { paramValue });
}
parameterExpressions.Add(paramValue);
}
var newExp = Expression.New(originalCtor, parameterExpressions);
var lambda = Expression.Lambda<DynamicConstructor<T>>(newExp, parameter);
return lambda.Compile();
}
使用System.Linq.Expressions;
公共静态dynamic构造函数getdynamic构造函数()
{
ConstructorInfo originalCtor=typeof(T).GetConstructors().First();
var参数=Expression.parameter(typeof(string[]),“args”);
var参数expressions=新列表();
ParameterInfo[]paramsInfo=originalCtor.GetParameters();
for(int i=0;i
注意,我添加了枚举处理,因为Parse不能像其他简单类型那样被调用
更新:
根据此处的注释,是一个扩展版本,用于发出将处理默认参数值的非泛型委托:
public static DynamicConstructor GetDynamicConstructor(Type type)
{
ConstructorInfo originalCtor = type.GetConstructors().First();
var parameter = Expression.Parameter(typeof(string[]), "args");
var parameterExpressions = new List<Expression>();
ParameterInfo[] paramsInfo = originalCtor.GetParameters();
for (int i = 0; i < paramsInfo.Length; i++)
{
Type paramType = paramsInfo[i].ParameterType;
// added check for default value on the parameter info.
Expression defaultValueExp;
if (paramsInfo[i].HasDefaultValue)
{
defaultValueExp = Expression.Constant(paramsInfo[i].DefaultValue);
}
else
{
// if there is no default value, then just provide
// the type's default value, but we could potentially
// do something else here
defaultValueExp = Expression.Default(paramType);
}
Expression paramValue;
paramValue = Expression.ArrayIndex(parameter, Expression.Constant(i));
if (paramType.IsEnum)
{
var enumParse = typeof(Enum).GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Type), typeof(string) }, null);
var call = Expression.Call(null, enumParse, new[] { Expression.Constant(paramType), paramValue });
paramValue = Expression.Convert(call, paramType);
}
else if (paramType != typeof(string))
{
var parseMethod = paramType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null);
if (parseMethod == null)
{
throw new Exception($"Cannot find Parse method for type {paramType} (parameter index:{i})");
}
paramValue = Expression.Call(null, parseMethod, new[] { paramValue });
}
// here we bounds check the array and emit a conditional expression
// that will provide a default value if necessary. Equivalent to
// something like i < args.Length ? int.Parse(args[i]) : default(int);
// Of course if the parameter has a default value that is used instead,
// and if the target type is different (long, boolean, etc) then
// we use a different parse method.
Expression boundsCheck = Expression.LessThan(Expression.Constant(i), Expression.ArrayLength(parameter));
paramValue = Expression.Condition(boundsCheck, paramValue, defaultValueExp);
parameterExpressions.Add(paramValue);
}
var newExp = Expression.New(originalCtor, parameterExpressions);
var lambda = Expression.Lambda<DynamicConstructor>(newExp, parameter);
return lambda.Compile();
}
}
公共静态dynamic构造函数getdynamic构造函数(类型)
{
ConstructorInfo originalCtor=type.GetConstructors().First();
var参数=Expression.parameter(typeof(string[]),“args”);
var参数expressions=新列表();
ParameterInfo[]paramsInfo=originalCtor.GetParameters();
for(int i=0;iusing System.Linq.Expressions;
public static DynamicConstructor<T> GetDynamicConstructor<T>()
{
ConstructorInfo originalCtor = typeof(T).GetConstructors().First();
var parameter = Expression.Parameter(typeof(string[]), "args");
var parameterExpressions = new List<Expression>();
ParameterInfo[] paramsInfo = originalCtor.GetParameters();
for (int i = 0; i < paramsInfo.Length; i++)
{
Type paramType = paramsInfo[i].ParameterType;
Expression paramValue = Expression.ArrayIndex(parameter, Expression.Constant(i));
if (paramType.IsEnum)
{
var enumParse = typeof(Enum).GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Type), typeof(string) }, null);
var call = Expression.Call(null, enumParse, new[] { Expression.Constant(paramType), paramValue });
paramValue = Expression.Convert(call, paramType);
}
else if (paramType != typeof(string))
{
var parseMethod = paramType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null);
if (parseMethod == null)
{
throw new Exception($"Cannot find Parse method for type {paramType} (parameter index:{i})");
}
paramValue = Expression.Call(null, parseMethod, new[] { paramValue });
}
parameterExpressions.Add(paramValue);
}
var newExp = Expression.New(originalCtor, parameterExpressions);
var lambda = Expression.Lambda<DynamicConstructor<T>>(newExp, parameter);
return lambda.Compile();
}
public static DynamicConstructor GetDynamicConstructor(Type type)
{
ConstructorInfo originalCtor = type.GetConstructors().First();
var parameter = Expression.Parameter(typeof(string[]), "args");
var parameterExpressions = new List<Expression>();
ParameterInfo[] paramsInfo = originalCtor.GetParameters();
for (int i = 0; i < paramsInfo.Length; i++)
{
Type paramType = paramsInfo[i].ParameterType;
// added check for default value on the parameter info.
Expression defaultValueExp;
if (paramsInfo[i].HasDefaultValue)
{
defaultValueExp = Expression.Constant(paramsInfo[i].DefaultValue);
}
else
{
// if there is no default value, then just provide
// the type's default value, but we could potentially
// do something else here
defaultValueExp = Expression.Default(paramType);
}
Expression paramValue;
paramValue = Expression.ArrayIndex(parameter, Expression.Constant(i));
if (paramType.IsEnum)
{
var enumParse = typeof(Enum).GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Type), typeof(string) }, null);
var call = Expression.Call(null, enumParse, new[] { Expression.Constant(paramType), paramValue });
paramValue = Expression.Convert(call, paramType);
}
else if (paramType != typeof(string))
{
var parseMethod = paramType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null);
if (parseMethod == null)
{
throw new Exception($"Cannot find Parse method for type {paramType} (parameter index:{i})");
}
paramValue = Expression.Call(null, parseMethod, new[] { paramValue });
}
// here we bounds check the array and emit a conditional expression
// that will provide a default value if necessary. Equivalent to
// something like i < args.Length ? int.Parse(args[i]) : default(int);
// Of course if the parameter has a default value that is used instead,
// and if the target type is different (long, boolean, etc) then
// we use a different parse method.
Expression boundsCheck = Expression.LessThan(Expression.Constant(i), Expression.ArrayLength(parameter));
paramValue = Expression.Condition(boundsCheck, paramValue, defaultValueExp);
parameterExpressions.Add(paramValue);
}
var newExp = Expression.New(originalCtor, parameterExpressions);
var lambda = Expression.Lambda<DynamicConstructor>(newExp, parameter);
return lambda.Compile();
}
}