我需要调用一个看起来像这样的方法:
public bool DoSomething<TEntity>(Expression<Func<TEntity, bool>> expression, Action<TEntity> action) where TEntity : class
但是TEntity仅在运行时才知道。
我知道如何调用这样的方法:
Type classType = GetType();
MethodInfo mInfo = classType.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
MethodInfo genericMInfo = mInfo.MakeGenericMethod(GetMyType());
Object result = genericMInfo.Invoke(this, <WHAT GOES HERE>);
如您所见,我不知道该函数传递什么。那就是与This Question的不同之处,在其中https://github.com/tensorflow/models/blob/master/research/object_detection/object_detection_tutorial.ipynb调用了没有参数的方法。
有什么办法可以做到吗?
编辑:完整示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Example
{
public class Program
{
static void Main(string[] args)
{
var example = new Example();
// Type know at compiletime:
example.DoSomething<MyClass>((obj) => obj.Number > 2, (obj) => obj.Number = 500);
// Type not know until runtime. Might be MyClass, MyOtherClass or MyNextClass
Type classType = example.GetType();
MethodInfo mInfo = classType.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
MethodInfo genericMInfo = mInfo.MakeGenericMethod(GetMyType());
var result = genericMInfo.Invoke(example, new object[] { /* Expression<Func<TEntity, bool>> and Action<TEntity> */ });
// My problem now is how to create this Expression and Action even if i know TEntity only at runtime
}
static Type GetMyType()
{
// Imagine some user-input or any other dark magic here. For the example i`ll just return a type
return typeof(MyOtherClass);
}
}
public class Example
{
public bool DoSomething<TEntity>(Expression<Func<TEntity, bool>> expression, Action<TEntity> action) where TEntity : MyClass
{
// Real code does something more useful, but its the same principle
var myList = new List<TEntity>(GetItems<TEntity>());
if (myList.Count > 0)
{
var entry = myList.AsQueryable().Where(expression).FirstOrDefault();
if (entry != null)
{
action(entry);
return true;
}
}
return false;
}
private IEnumerable<T> GetItems<T>()
{
// Real code does something diffrent
for (int i = 0; i < 5; i++)
{
yield return (T)Activator.CreateInstance(typeof(T), i);
}
}
}
public class MyClass
{
public MyClass(int number)
{
Number = number;
}
public int Number { get; set; }
}
public class MyOtherClass : MyClass
{
public MyOtherClass(int number)
: base(number++)
{
}
}
public class MyNextClass : MyClass
{
public MyNextClass(int number)
: base(number--)
{
}
}
}
答案 0 :(得分:0)
很遗憾,it's not possible to define generic anonymous methods。
最大的问题是:您的表情/动作来自哪里?
从头开始,可能的解决方案包括将您的操作声明为单独的方法,或者使用辅助方法来创建您的操作/表达式。
// Create a helper method to create the expression
public static Expression<Func<TEntity, bool>> MakeExpression<TEntity>()
{
// your custom expression here
return x => true;
}
// Declare your action as a generic method
public static void MyAction<TEntity>(TEntity input)
{
// your action here
}
// Then you can use it like this:
var func = typeof(Example).GetMethod("MakeExpression", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(classType).Invoke(example, new object[0]);
var action = typeof(Example).GetMethod("MyAction", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(classType ).CreateDelegate(typeof(Action<>).MakeGenericType(classType));
genericMInfo.Invoke(example, new object[] { func, action });
您也可以对操作使用相同的“表达式工厂”方法:
public static Action<TEntity> MakeAction<TEntity>()
{
// your custom action here.
return e => { };
}
// Then:
var action = typeof(Example).GetMethod("MakeAction", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(classType).Invoke(example, new object[0]);
另一种可能的解决方案包括使用Expression
类的building your expression/action dynamically。
// Simple(!) example
var func = Expression.Lambda(Expression.Constant(true), Expression.Parameter(classType));