I am making a framework that supports plugins, therefore it load classes defined in plugin dlls when the application starts.
foreach (Type t in assembly.GetTypes()) {
if (t.IsAssignableTo(typeof(AIGameBodyBehaviour))) {
AIGameBodyBehaviourFactory factory = new AIGameBodyBehaviourFactory() {
Id = t.Name,
NewAIGameBodyBehaviour = Expression.Lambda<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>>(
Expression.New(
t.GetConstructor(new Type[] {typeof(AIGameBodyBehaviourFactoryArguments) }),
new Expression[] {
//stuck at here
}
),
new ParameterExpression[] {
Expression.Parameter(typeof(AIGameBodyBehaviourFactoryArguments), "arguments")
}
).Compile()
};
EntityLoaderInterface.AddAIGameBodyBehaviourFactory(factory);
}
}
As shown above, the complied lambda takes a parameter of type AIGameBodyBehaviourFactoryArguments and return an instance of AIGameBodyBehaviour. The body of the lambda function is a call to the constructor of the subclass of AIGameBodyBehaviour defined by user.
The parameter of the lambda expression is named "arguments". This name should be reused as the expression repressenting the value to be passed into the constructor. However, I cannot findout how to do this even after examining the documentation provided by Microsoft and some research via Google.
When you are stuck with expressions, you can consider SharpLab. If I understood you correctly, you want to have an expression that looks like this:
Expression<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>> expression =
(arguments) => new AIGameBodyBehaviour(arguments);
SharpLab will show you that the compiler will turn this line into
ParameterExpression parameterExpression = Expression.Parameter(typeof(AIGameBodyBehaviourFactoryArguments), "arguments");
ConstructorInfo constructor = (ConstructorInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/);
Expression[] array = new Expression[1];
array[0] = parameterExpression;
NewExpression body = Expression.New(constructor, (IEnumerable<Expression>)array);
ParameterExpression[] array2 = new ParameterExpression[1];
array2[0] = parameterExpression;
Expression<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>> expression = Expression.Lambda<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>>(body, array2);
You can see that the same instance for ParameterExpression
is used as the second parameter in Expression.New
and in the second parameter in Expression.Lambda
. Hence your code should look like this:
foreach (Type t in assembly.GetTypes()) {
if (t.IsAssignableTo(typeof(AIGameBodyBehaviour))) {
var parameterExpression = Expression.Parameter(typeof(AIGameBodyBehaviourFactoryArguments), "arguments");
AIGameBodyBehaviourFactory factory = new AIGameBodyBehaviourFactory() {
Id = t.Name,
NewAIGameBodyBehaviour = Expression.Lambda<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>>(
Expression.New(
t.GetConstructor(new Type[] {typeof(AIGameBodyBehaviourFactoryArguments) }),
new Expression[] {
parameterExpression
}
),
new ParameterExpression[] {
parameterExpression
}
).Compile()
};
EntityLoaderInterface.AddAIGameBodyBehaviourFactory(factory);
}
}