您可以將它作爲object[]
發送,然後在方法生成期間使用特定項目。
基本上低於"Test Long String".Substring(5);
代碼會產生這樣的方法:
object DynamicMethod(object[] params)
{
return "Test Long String".Substring((int)params[0]);
}
缺點是結果,而params的對象,因此它會產生不必要的拳擊\拆箱操作,但如果你知道的簽名,那麼你就可以寫通用將使用特定類型的實現。
示例代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
public class Program
{
public static void Main(string[] args)
{
// test non static method with result
string test = "Test String";
MethodInfo method = typeof(string).GetMethod("Substring", BindingFlags.Public | BindingFlags.Instance, null, new Type[]{typeof(int)},null);
Func<object[], object> lazyMethod = CreateLazyMethodWithResult(test, method);
object result = lazyMethod(new object[] { 5 });
Console.WriteLine(result);
Console.WriteLine();
// test static method with no result
var staticMethod = typeof(Program).GetMethod("StaticMethod", BindingFlags.Static | BindingFlags.Public);
var staticAction = CreateLazyStaticMethodWithNoResult(staticMethod);
staticAction(new object[]{"Test message"});
Console.WriteLine();
//test static method with result
var staticMethodWithResult = typeof(Program).GetMethod("StaticMethodWithResult", BindingFlags.Static | BindingFlags.Public);
var staticActionWithResult = CreateLazyStaticMethodWithResult(staticMethodWithResult);
Console.WriteLine(staticActionWithResult(new object[] { "Test message" }));
Console.WriteLine();
// sample with constructor
var constructorCall = typeof(TestClass).GetConstructors().First();
var constructorAction = GenerateLazyConstructorCall(constructorCall);
var createdObject = constructorAction(new object[] { "Test message" });
Console.WriteLine("Created type is " + createdObject.GetType().FullName);
}
//Test class
public class TestClass
{
public TestClass(string message)
{
Console.WriteLine("----Constructor is called with message - " + message);
}
}
public static void StaticMethod(string message)
{
Console.WriteLine("----Static method is called with " + message);
}
public static string StaticMethodWithResult(string message)
{
Console.WriteLine("----Static method with result is called with " + message);
return "Hello from static method";
}
public static Func<object[], object> CreateLazyMethodWithResult(object instance, MethodInfo method)
{
ParameterExpression allParameters;
var methodCall = GenerateCallExpression(instance, method, out allParameters);
var lambda = Expression.Lambda<Func<object[], object>>(methodCall, allParameters);
return lambda.Compile();
}
public static Action<object[]> CreateLazyMethodWithNoResult(object instance, MethodInfo method)
{
ParameterExpression allParameters;
var methodCall = GenerateCallExpression(instance, method, out allParameters);
var lambda = Expression.Lambda<Action<object[]>>(methodCall, allParameters);
return lambda.Compile();
}
public static Func<object[], object> CreateLazyStaticMethodWithResult(MethodInfo method)
{
ParameterExpression allParameters;
var methodCall = GenerateCallExpression(null, method, out allParameters);
var lambda = Expression.Lambda<Func<object[], object>>(methodCall, allParameters);
return lambda.Compile();
}
public static Action<object[]> CreateLazyStaticMethodWithNoResult(MethodInfo method)
{
ParameterExpression allParameters;
var methodCall = GenerateCallExpression(null, method, out allParameters);
var lambda = Expression.Lambda<Action<object[]>>(methodCall, allParameters);
return lambda.Compile();
}
/// <summary>
/// Generate expression call
/// </summary>
/// <param name="instance">If instance is NULL, then it method will be treated as static method</param>
private static MethodCallExpression GenerateCallExpression(object instance, MethodBase method, out ParameterExpression allParameters)
{
var parameters = GenerateParameters(method, out allParameters);
var methodInfo = method as MethodInfo;
// it's non static method
if (instance != null)
{
var instanceExpr = Expression.Convert(Expression.Constant(instance), instance.GetType());
return Expression.Call(instanceExpr, methodInfo, parameters.ToArray());
}
// it's static method
return Expression.Call(methodInfo, parameters.ToArray());
}
public static Func<object[], object> GenerateLazyConstructorCall(ConstructorInfo constructor)
{
ParameterExpression allParameters;
var parameters = GenerateParameters(constructor, out allParameters);
var newExpr = Expression.New(constructor, parameters.ToArray());
var lambda = Expression.Lambda<Func<object[], object>>(newExpr, allParameters);
return lambda.Compile();
}
private static List<Expression> GenerateParameters(MethodBase method, out ParameterExpression allParameters)
{
allParameters = Expression.Parameter(typeof(object[]), "params");
ParameterInfo[] methodMarameters = method.GetParameters();
List<Expression> parameters = new List<Expression>();
for (int i = 0; i < methodMarameters.Length; i++)
{
var indexExpr = Expression.Constant(i);
var item = Expression.ArrayIndex(allParameters, indexExpr);
var converted = Expression.Convert(item, methodMarameters[i].ParameterType);
parameters.Add(converted);
}
return parameters;
}
}
實際的工作例如:https://dotnetfiddle.net/lHB2kE
UPDATE 我更新的代碼樣本調用方法和構造函數:
- 實例方法沒有返回對象
- 實例方法有一些返回對象
- 沒有返回對象的靜態方法
- 一些返回對象的靜態方法
- 樣品的構造使用
:感謝名單我怎麼能像調用構造函數:'ctor.Invoke(新對象[] {10})' – Mohsen 2014-10-29 10:28:06
:我怎樣才能調用靜態(這得到我:'System.Boolean'類型的表達式不能用於返回類型'System.Object') – Mohsen 2014-10-29 10:59:06
我已經更新了答案樣本靜態方法。如果你需要調用返回'Boolean'的靜態方法,那麼你可以在'Main'方法中檢查'CreateLazyStaticMethodWithResult'方法和使用它的樣本。 – 2014-10-29 11:26:58