我希望代码剪切说明我的问题。
我需要Invoke
CallEvent
方法,就像它在out-comment行中一样。
我无法访问ThirdParty
或AnotherThirdParty
类
就我而言:
public class ThirdParty
{
private struct MsgType
{ }
private static void AnotherFunc(MsgType msg)
{ }
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{ }
}
public class MyClass
{
public static void Main()
{
Type MsgType = typeof(ThirdParty).GetNestedType(
"MsgType", BindingFlags.Instance | BindingFlags.NonPublic);
object msg = Activator.CreateInstance(MsgType);
MethodInfo CallEvent = typeof(AnotherThirdParty).GetMethod("CallEvent");
CallEvent = CallEvent.MakeGenericMethod(MsgType);
MethodInfo AnotherFunc = typeof(ThirdParty).GetMethod(
"AnotherFunc", BindingFlags.Static | BindingFlags.NonPublic);
CallEvent.Invoke(null, new object[] {???, msg});
//CallEvent<MsgType>((int x) => new Action<MsgType>(AnotherFunc), msg);
// I can't get my head around how to solve this (Action<msgtype>)
}
}
我也尝试过:
CallEvent.Invoke(null, new object[]
{
new Func<int, Action<object>>((int x) =>
new Action<object>((object y) =>
AnotherFunc.Invoke(null, new object[] { y }))),
msg
});
我得到以下例外:
System.ArgumentException:类型的对象 'System.Func2 [System.Int32,System.Action1 [System.Object]]'不能 转换为类型 “System.Func2 [System.Int32,System.Action1 [第三方+ MSGTYPE]]。
我该怎么办?
答案 0 :(得分:7)
public class ThirdParty
{
private struct MsgType { }
private static void AnotherFunc(MsgType msg)
{
// Inserted to demonstrate getting here
Console.WriteLine($"HEY: {msg}");
}
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{
// Inserted to demonstrate calling the func and then
// the action
action(12)(arg);
}
}
public static void Main()
{
var msgTypeType =
typeof(ThirdParty).GetNestedType("MsgType", BindingFlags.NonPublic);
// This is the message type we're passing (presumably you'll do more with it)
var ourMsgTypeArg = Activator.CreateInstance(msgTypeType);
// Get the reference to the CallEvent method
var callEventMethod =
typeof(AnotherThirdParty).GetMethod("CallEvent", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(msgTypeType);
// Get the reference to the AnotherFunc method
var anotherFunc =
typeof(ThirdParty).GetMethod("AnotherFunc", BindingFlags.NonPublic | BindingFlags.Static);
// Build the func to pass along to CallEvent
var func = CreateFunc(msgTypeType, anotherFunc);
// Call the CallEvent<MsgType> method.
callEventMethod.Invoke(null, new object[] {
func,
ourMsgTypeArg
});
}
private static Delegate CreateFunc(Type msgType, MethodInfo anotherFunc)
{
// The func takes an int
var intArg = Expression.Parameter(typeof(int));
// The action takes a msgType
var msgTypeArg = Expression.Parameter(msgType);
// Represent the call out to "AnotherFunc"
var call = Expression.Call(null, anotherFunc, msgTypeArg);
// Build the action to just make the call to "AnotherFunc"
var action = Expression.Lambda(call, msgTypeArg);
// Build the func to just return the action
var func = Expression.Lambda(action, intArg);
// Compile the chain and send it out
return func.Compile();
}
此代码按您的要求运行并打印以下内容:
HEY: UserQuery+ThirdParty+MsgType
答案 1 :(得分:2)
这似乎在运行:
MethodInfo miCreateDelegate = typeof(MethodInfo).GetMethod("CreateDelegate", new[] { typeof(Type), typeof(Object) });
var ActionType = typeof(Action<>).MakeGenericType(MsgType);
var lambdabody = Expression.Convert(Expression.Call(Expression.Constant(AnotherFunc), miCreateDelegate, new[] { Expression.Constant(ActionType), Expression.Constant(null) }), ActionType);
var intparm = Expression.Parameter(typeof(int));
var lambda = Expression.Lambda(lambdabody, intparm);
CallEvent.Invoke(null, new object[] {
lambda.Compile(),
msg
});
更完整的答案是我是如何产生的?我使用LINQPad来编译一个更简单,类似的表达式,将string
替换为MsgType
到Expression
:
public static void afunc(string x) { }
Expression<Func<int, Action<string>>> lambda = (int x) => new Action<string>(afunc);
然后我使用LINQPad Dump()
函数输出表达式树。
lambda.Dump();
然后,MSDN Expression文档中的一些洞察力给了我正确的静态方法来创建片段。我已经知道如何从LINQPad的扩展方法实例化泛型类型,它可以动态创建匿名类型以扩展Dump()
以从匿名对象中排除字段,我知道如何从扩展LINQ的扩展方法创建lambdas一个适当的SQL可翻译的左和右连接操作。
答案 2 :(得分:1)
使用Delegate.CreateDelegate
方法构造Action<MsgType>
对象。使用Expression.Lambda<>
构建Func<int,Action<T>>
:
var actionType = typeof(Action<>).MakeGenericType(MsgType);
var funcType = typeof(Func<,>).MakeGenericType(typeof(int), actionType);
var p1 = Expression.Parameter(typeof(int));
var p2 = Expression.Parameter(actionType);
var delegate = Expression.Constant(Delegate.CreateDelegate(actionType, AnotherFunc), funcType);
var lambda = Expression.Lambda(delegate, p1, p2);
CallEvent.Invoke(null, new object[] {
lambda.Compile()
, msg
});
答案 3 :(得分:0)
这将起作用并将打印A但功能工厂对我来说是个谜,所以我刚刚返回创建的委托。这与.net标准1.1
兼容static void Main(string[] args)
{
Type MsgType = typeof(ThirdParty).GetNestedType(
"MsgType", BindingFlags.Instance | BindingFlags.NonPublic);
object msg = Activator.CreateInstance(MsgType);
MethodInfo CallEvent = typeof(AnotherThirdParty).GetMethod("CallEvent");
CallEvent = CallEvent.MakeGenericMethod(MsgType);
MethodInfo AnotherFunc = typeof(ThirdParty).GetMethod(
"AnotherFunc", BindingFlags.Static | BindingFlags.NonPublic);
var actionType = typeof(Action<>).MakeGenericType(MsgType);
var actionDelegate = AnotherFunc.CreateDelegate(actionType);
var param = Expression.Parameter(typeof(int));
var funcDelegate = Expression.Lambda(Expression.Constant(actionDelegate),param).Compile();
CallEvent.Invoke(null, new []{ funcDelegate, msg });
Console.ReadLine();
}
public class ThirdParty
{
private struct MsgType
{ }
private static void AnotherFunc(MsgType msg)
{
Console.WriteLine("A");
}
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{
action(1)(arg);
}
}