动态类实例化

时间:2018-06-11 21:21:58

标签: c# .net dynamic lambda

我有从基类派生的类,并希望在运行时动态实例化这些类。使用以下代码,我可以使用默认构造函数构建一个类:

public abstract class Employee : IEmployeeInterface
{    
 public string Name { get; set; }

 public Employee() { }

 public Employee(string name)
 {
    Name = name;
 }    
}

public static class EmployeeBot
{
    static readonly Func<string, Func<Employee>> EmployeeBotFunction = x =>
    Expression.Lambda<Func<Employee>>(
    Expression.New(Type.GetType(x).GetConstructor(Type.EmptyTypes))
    ).Compile();

    public static Employee InstantiateNewEmployee(string type)
    {
        string argumentType = string.Format("{1}.{0}", type.ToString(), MethodBase.GetCurrentMethod().DeclaringType.Namespace);
        return EmployeeBotFunction(argumentType).Invoke();
    }
}

Worker实现了Employee,可以使用以下方式创建:

Employee employee = EmployeeBot.InstantiateNewEmployee("Worker");

然后,由于Worker具有与Employee完全相同的方法,因此调用它们将按预期从工人类中提供结果。

但是,我无法弄清楚如何正确实现类似的代码来使用带参数的构造函数。例如:

static readonly Func<string, Type[], Func<string, Employee>> NewEmployee = (x, y) =>
Expression.Lambda<Func<string, Employee>>(
Expression.New(Type.GetType(x).GetConstructor(y))
).Compile();

public static Employee InstantiateNewEmployee(string type, string Name)
{
 Type[] construct = new Type[] { typeof(string) }; 
 string argumentType = string.Format("{1}.{0}", type.ToString(), MethodBase.GetCurrentMethod().DeclaringType.Namespace);
 return NewEmployee(argumentType, construct).Invoke(Name);
}

调用此方法会抛出异常:

  

EmployeesTests.InstantiateEmployeeWithName抛出异常:   System.InvalidOperationException:只能在Type上调用Method   Type.IsGenericParameter为true。

如何更改NewEmployee函数以接受第二个构造函数所需的参数?

1 个答案:

答案 0 :(得分:1)

我已经在@JSteward的帮助下回答了这个问题,谢谢!

结合不同版本的public class Worker : Employee并修复了一个愚蠢的错误,我能够解决这个问题。你不能实例化一个抽象类,所以我的构造函数应该在一个派生类上,例如public abstract class Employee而不是Expression.New(Type.GetType(x).GetConstructor(y));

实际错误是null的构造函数参数是static readonly Func<string, Type[], ParameterExpression[], Func<string, Employee>> NewEmployee = (x, y, z) => Expression.Lambda<Func<string, Employee>>( Expression.New(Type.GetType(x).GetConstructor(y), z) , z).Compile(); public static Employee InstantiateNewEmployee(string type, string Name) { Type[] construct = new Type[] { typeof(string) }; string argumentType = string.Format("{1}.{0}", type.ToString(), MethodBase.GetCurrentMethod().DeclaringType.Namespace); ParameterExpression[] arguments = new ParameterExpression[] { Expression.Parameter(typeof(string)) }; return NewEmployee(argumentType, construct, arguments).Invoke(Name); } ,因为它没有在Worker上定义。

第二个例子现在变成了; (虽然我确信这可以改进!)。

def likeMovement(pID):
    print("Give a rating for the movement with #id:%s" %pID)
    rate=input("Give from 0-5: ")
    userID=str(1)
    print(rate,type(rate))
    print(pID,type(pID))
    print(userID,type(userID))
    cursor=con.cursor()
    sqlquery='''UDPATE likesartmovement SET likesartmovement.rating=%s WHERE 
    likesartmovement.artisticID=? AND likesartmovement.userID=?''' % (rate,), 
    (pID,userID)
    cursor.execute(sqlquery)

@JSteward评论的帖子实际上已经概括了这个要求:linq-expressions-creating-objects

感谢您的帮助以及博客的评论。

  

但很高兴看到我并不是唯一一个疯狂地以这种方式使用表达式的人!