C# Activator.CreateInstance以类作为参数调用构造函数

C# Activator.CreateInstance以类作为参数调用构造函数,c#,reflection,activator,C#,Reflection,Activator,嗨,我正在尝试动态地执行以下操作 我正在使用我自己的CreateInstance方法,但这已经用Activator.CreateInstance进行了测试 IPEndPoint newObject = new IPEndPoint(IPAddress.Any, 80); 尝试使用activator时出现错误,无法将System.RuntimeType转换为IPAddress public static object CreateInstance(Type context, object

嗨,我正在尝试动态地执行以下操作 我正在使用我自己的CreateInstance方法,但这已经用Activator.CreateInstance进行了测试

IPEndPoint newObject = new IPEndPoint(IPAddress.Any, 80);
尝试使用activator时出现错误,无法将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;
    }
公共静态对象CreateInstance(类型上下文,对象[]参数)
{
List argTypes=new List();
foreach(参数中的对象参数)
Add(GetType(Param));
ConstructorInfo[]类型=context.GetConstructors();
foreach(类型中的ConstructorInfo节点)
{
ParameterInfo[]Args=node.GetParameters();
if(Params.Length==Args.Length)
{
bool[]cond=新bool[参数长度];
对于(int i=0;i
这是数组中参数的外观 [0]{Name=“IPAddress”FullName=“System.Net.IPAddress”} [1] 八十

这是调用代码,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;
}
私有对象CreateInstance(ObjectCreationExpression Exp)
{
对象上下文=GetContext(Exp.Identifier);//获取类类型
类型t=(类型)上下文;
object[]Params=GetParams(Exp.ArgumentList).ToArray();
object newObject=Activator.CreateInstance(t,Params);
返回newObject;
}
公共静态对象GetContext(字符串类名称)
{
返回ParseNamespace(“System.dll”,classname);
}
私有静态对象ParseNamespace(字符串命名空间,字符串类名)//在System.dll中查找类
{
string DotNetPath=ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.VersionLatest);
Assembly Asm=Assembly.LoadFile(DotNetPath+@“\”+命名空间);
Type[]Types=Asm.GetExportedTypes();
foreach(类型中的类型节点)
{
if(Node.Name==classname)
返回节点;
}
返回null;
}
私有列表GetParams(NodeCollection参数)
{
列表参数=新列表();
foreach(参数中的ArgumentNode节点)
{
if(node.Expression为MemberAccessExpression)
{
MemberAccessExpression=(MemberAccessExpression)node.Expression;
类型值=(类型)GetContext(exp);
字符串名称=DirectCast(exp.Right).Identifier;
if(value.IsEnum)
{
字符串[]名称=DirectCast(值).GetEnumNames();
数组项=DirectCast(value).GetEnumValues();
Add(item.GetValue(names.ToList().IndexOf(name));
}
其他的
{
类型项=值。GetMember(名称)[0]。ReflectedType;
参数。添加(项目);
}
}
其他的
Add((Int32)ParseType(node.Expression));
}
返回参数;
}

ObjectCreationExpression是一个自定义类,包含用于创建新实例的已解析源代码,两个主要属性是ArgumentList,ArgumentList是用作参数的值或标识符的集合,另一个属性是我们正在创建的类型的标识符

您已经编写了一个很好的实现来创建对象实例,但是它有一些缺陷。我已经在下面的代码中更正了它们

    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;
    }
注意我可能无法纠正上述示例中的所有缺陷,我只是让它适用于您的场景,即您调用代码

IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), IPAddress.Any, 80);
IPEndPoint newObject = CreateInstance<IPEndPoint>(IPAddress.Any, 80);
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), new object[] { IPAddress.Any, 80});
泛型实现

    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);
    }
    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);
    }
此代码也可以为空参数

乙二醇

我简化了一点,还处理了默认构造函数的空参数。还有其他几张支票

因此,即使您也可以
构造值类型
,此更改也会使其完全动态

乙二醇

您案例的示例

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);

值得一提的是,这是我对您的方法的重构:

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;
}
公共静态对象CreateInstance(类型为pContext,参数对象[]参数){
var constructors=pContext.GetConstructors();
foreach(构造函数中的var构造函数){
var parameters=constructor.GetParameters();
if(parameters.Length!=pArguments.Length)
继续;
//假设您需要一个匹配的构造函数
//不仅仅是与前两种类型匹配的一种
布尔失败=错误;
对于(int x=0;x
请注意,您似乎将“参数”和“参数”的概念颠倒过来了。“参数”是接受值的方法的命名部分。“参数”是您传递的实际值


除此之外,听起来您的问题更多地与所传递的值有关,而不是与方法的实现有关。

您传递的第一个参数是
类型
对象,而不是实际的
IPAddress
。在没有看到调用代码的情况下,我们无法知道这种情况是如何发生的。您说在使用
Activator.CreateInstance
时出现了“无法转换”错误,但您没有说明
CreateInstance
方法的问题。请去掉
if(cond[0]==true…
检查。这似乎是调试代码。它不适合于通用对象创建。感谢您的回复,不幸的是,我不能使用typeof或类型约束,因为这应该是动态的,并且将用于其他类,而不仅仅是IPAddress。我希望您可以
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);
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;
}