[英]Activator.CreateInstance calling constructor with class as parameter
Hi I'm trying to do the following dynamically I'm using my own CreateInstance method but this has been tested with Activator.CreateInstance 嗨,我正在尝试动态地执行以下操作,我正在使用自己的CreateInstance方法,但是已经通过Activator.CreateInstance测试过
IPEndPoint newObject = new IPEndPoint(IPAddress.Any, 80);
when I try to use activator I get error, cannot convert System.RuntimeType to IPAddress 当我尝试使用激活器时出现错误,无法将System.RuntimeType转换为IPAddress
public static object CreateInstance(Type context, object[] Params)
{
List<Type> argTypes = new List<Type>();
foreach (object Param in Params)
argTypes.Add(GetType(Param));
ConstructorInfo[] Types = context.GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
if (Params.Length == Args.Length)
{
bool[] cond = new bool[Params.Length];
for (int i = 0; i < Params.Length; i++)
if (argTypes[i] == Args[i].ParameterType) cond[i] = true;
if (cond[0] == true & cond[1] == true)
return node.Invoke(Params);
}
}
return null;
}
This is what the Params look like in the array [0] {Name = "IPAddress" FullName = "System.Net.IPAddress"} [1] 80 这就是参数在数组[0] {Name =“ IPAddress” FullName =“ System.Net.IPAddress”}中的样子[1] 80
this is the calling code, prob should have provided it before so you know what I'm trying to do as you can see it parses string values that represent classes, this is why I can't use typeof or typeconstraints. 这是调用代码,prob应该已经提供了它,所以您知道我要尝试执行的操作,因为您可以看到它解析表示类的字符串值,这就是为什么我不能使用typeof或typeconstraints的原因。
private object CreateInstance(ObjectCreationExpression Exp)
{
object context = GetContext(Exp.Identifier); //Gets the class type
Type t = (Type)context;
object[] Params = GetParams(Exp.ArgumentList).ToArray();
object newObject = Activator.CreateInstance(t, Params);
return newObject;
}
public static object GetContext(string classname)
{
return ParseNamespace("System.dll", classname);
}
private static object ParseNamespace(string Namespace, string classname) //Looks up class in System.dll
{
string DotNetPath = ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.VersionLatest);
Assembly Asm = Assembly.LoadFile(DotNetPath + @"\" + Namespace);
Type[] Types = Asm.GetExportedTypes();
foreach (Type Node in Types)
{
if (Node.Name == classname)
return Node;
}
return null;
}
private List<object> GetParams(NodeCollection<ArgumentNode> Params)
{
List<object> Arguments = new List<object>();
foreach (ArgumentNode node in Params)
{
if (node.Expression is MemberAccessExpression)
{
MemberAccessExpression exp = (MemberAccessExpression)node.Expression;
Type value = (Type)GetContext(exp);
string name = DirectCast<IdentifierExpression>(exp.Right).Identifier;
if (value.IsEnum)
{
string[] names = DirectCast<Type>(value).GetEnumNames();
Array item = DirectCast<Type>(value).GetEnumValues();
Arguments.Add(item.GetValue(names.ToList().IndexOf(name)));
}
else
{
Type item = value.GetMember(name)[0].ReflectedType;
Arguments.Add(item);
}
}
else
Arguments.Add((Int32)ParseType(node.Expression));
}
return Arguments;
}
ObjectCreationExpression is a custom class that contains parsed sourcecode for creating a new instance, the two main properties are ArgumentList which is a collection of values or identifiers to be used as parameters, the other property is an identifier for the type we are creating ObjectCreationExpression是一个自定义类,其中包含用于创建新实例的已解析源代码,两个主要属性是ArgumentList,它是用作参数的值或标识符的集合,另一个属性是我们正在创建的类型的标识符
You have wrote a nice implementation to create object instance, however it had some flaws. 您已经编写了一个不错的实现来创建对象实例,但是它存在一些缺陷。 I've corrected them in the code below
我已经在下面的代码中更正了它们
public static object CreateInstance(Type context, params object[] Params) // params keyword for array
{
List<Type> argTypes = new List<Type>();
//used .GetType() method to get the appropriate type
//Param can be null so handle accordingly
foreach (object Param in Params)
argTypes.Add((Param ?? new object()).GetType());
ConstructorInfo[] Types = context.GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
if (Params.Length == Args.Length)
{
bool[] cond = new bool[Params.Length];
//handle derived types
for (int i = 0; i < Params.Length; i++)
if (Args[i].ParameterType.IsAssignableFrom(argTypes[i])) cond[i] = true;
if (cond[0] && cond[1])
return node.Invoke(Params);
}
}
return null;
}
calling code 呼叫码
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), IPAddress.Any, 80);
Note I may not be able to correct every flaw in the sample above, I just made it workable for your scenario ie you calling code 注意我可能无法纠正上面示例中的每个缺陷,只是使它适用于您的情况,即您调用代码
Generics implementation 泛型实现
public static T CreateInstance<T>(params object[] Params) where T : class // params keyword for array
{
List<Type> argTypes = new List<Type>();
//used .GetType() method to get the appropriate type
//Param can be null so handle accordingly
foreach (object Param in Params)
argTypes.Add((Param ?? new object()).GetType());
ConstructorInfo[] Types = typeof(T).GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
if (Params.Length == Args.Length)
{
bool[] cond = new bool[Params.Length];
//handle derived types
for (int i = 0; i < Params.Length; i++)
if (Args[i].ParameterType.IsAssignableFrom(argTypes[i])) cond[i] = true;
if (cond[0] && cond[1])
return (T)node.Invoke(Params);
}
}
return default(T);
}
calling code 呼叫码
IPEndPoint newObject = CreateInstance<IPEndPoint>(IPAddress.Any, 80);
Fully dynamic object construction 完全动态的对象构造
public static object CreateInstance(Type pContext, object[] Params)
{
List<Type> argTypes = new List<Type>();
//used .GetType() method to get the appropriate type
//Param can be null so handle accordingly
if (Params != null)
foreach (object Param in Params)
{
if (Param != null)
argTypes.Add(Param.GetType());
else
argTypes.Add(null);
}
ConstructorInfo[] Types = pContext.GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
// Params can be null for default constructors so use argTypes
if (argTypes.Count == Args.Length)
{
bool areTypesCompatible = true;
for (int i = 0; i < Params.Length; i++)
{
if (argTypes[i] == null)
{
if (Args[i].ParameterType.IsValueType)
{
//fill the defaults for value type if not supplied
Params[i] = CreateInstance(Args[i].ParameterType, null);
argTypes[i] = Params[i].GetType();
}
else
{
argTypes[i] = Args[i].ParameterType;
}
}
if (!Args[i].ParameterType.IsAssignableFrom(argTypes[i]))
{
areTypesCompatible = false;
break;
}
}
if (areTypesCompatible)
return node.Invoke(Params);
}
}
//delegate type to Activator.CreateInstance if unable to find a suitable constructor
return Activator.CreateInstance(pContext);
}
calling code 呼叫码
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), new object[] { IPAddress.Any, 80});
this code can also null parameters 此代码还可以将参数设为空
eg 例如
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), new object[] { IPAddress.Any, null});
I simplified it a bit and also handled null parameters for default constructors also. 我对其进行了简化,还为默认构造函数处理了空参数。 and couple of other checks
和其他几张支票
so this change makes it complete dynamic even you can construct value types
too 因此,即使您也可以
construct value types
,此更改也使其完全动态
eg 例如
int obj = (int)CreateInstance(typeof(int), null);
Example for your case 您的案例
object context = GetContext(Exp.Identifier);
Type t = (Type)context;
object[] Params = GetParams(Exp.ArgumentList).ToArray();
//use the above defined method and it will work as expected
object newObject = CreateInstance(t, Params);
For what it's worth, this is my refactoring of your method: 对于它的价值,这是我对您的方法的重构:
public static object CreateInstance(Type pContext, params object[] pArguments) {
var constructors = pContext.GetConstructors();
foreach (var constructor in constructors) {
var parameters = constructor.GetParameters();
if (parameters.Length != pArguments.Length)
continue;
// assumed you wanted a matching constructor
// not just one that matches the first two types
bool fail = false;
for (int x = 0; x < parameters.Length && !fail; x++)
if (!parameters[x].ParameterType.IsInstanceOfType(pArguments[x]))
fail = true;
if (!fail)
return constructor.Invoke(pArguments);
}
return null;
}
Note that you seem to have the notion of "parameter" and "argument" backwards. 请注意,您似乎反过来具有“参数”和“参数”的概念。 A "parameter" is the named part of the method that accepts a value.
“参数”是接受值的方法的命名部分。 An "argument" is the actual value that you pass.
“参数”是您传递的实际值。
Aside from that, it sounds like your problem has more to do with the values you are passing, than the implementation of the method. 除此之外,听起来您的问题更多地与传递的值有关,而不是方法的实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.