问题描述
我有一个私有静态泛型方法,我想使用反射调用,但实际上我想将其捆绑"在另一个方法中. C#7.0支持本地功能,因此这绝对有可能.
I have a private static generic method I want to call using reflection, but really I want to 'bundle' it inside of another method. C# 7.0 supports local functions so this is definitely possible.
您会说为什么不直接打电话呢?"但是我正在使用它来获得以强类型使用方式使用对象和System.Type的能力,因此我需要动态调用它.如果我有此代码,则该代码已经可以使用,因为它是自己的私有静态泛型方法.
You would say "why don't you just call it directly?" but I'm using it to get the ability to use an object and System.Type in a strongly typed manner so I need to call it dynamically. This code already works if I have it as it's own private static generic method.
private static void HandleResponse(object data, Type asType)
{
var application = typeof(Program);
application
.GetMethod(nameof(UseAs), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(asType)
.Invoke(null, new object[] { data });
}
public static void UseAs<T>(T obj)
{
Console.WriteLine($"Object is now a: {typeof(T)}:");
};
上面的代码有效.如果我通过:
The above code works. If I pass in:
data: new TestObject(),
type: typeof(TestObject)
实际上,我将在UseAs中拥有一个TestObject.
I'll actually have a TestObject inside UseAs.
所以,我想将所有这些都放在一个方法中,就像这样:
So, I wanted to put this all in a single method, like so:
private static void HandleResponse(object data, Type asType)
{
void useAs<T>(T obj)
{
Console.WriteLine($"Object is now a: {typeof(T)}:");
};
var application = typeof(Program);
application
.GetMethod(nameof(UseAs), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(asType)
.Invoke(null, new object[] { data });
}
不幸的是,GetMethod代码不再起作用.我听说在编译时,编译器会将任何本地函数转换为静态方法,因此我跳到立即窗口并运行:
Unfortunately, the GetMethod code no longer works. I had heard that on compile time the compiler converts any local functions to static methods so I popped down to the immediate window and ran:
application.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
...而且,我实际上确实看到了此响应:
... And, I actually DO see this response:
{System.Reflection.MethodInfo[3]}
[0]: {Void Main(System.String[])}
[1]: {Void HandleResponse(System.Object, System.Type)}
[2]: {Void <HandleResponse>g__useAs1_0[T](T)}
这是列表上的最后一个方法.有谁知道您将如何以合理的方式访问类似的方法?
It's the last method on the list. Does anyone have any idea how you would access a method like that in a reasonable way?
谢谢!
我确实可以将UseAs用作普通的私有静态方法.它只是不会在其他任何地方使用,所以我想将其全部打包"在一个方法中.
I can indeed use UseAs as an ordinary private static method. It's just not going to be used anywhere else so I wanted to "package" it all up inside one method.
此外,这实际上应该是一个有关查找局部函数的问题,而在StackOverflow上的其他任何地方似乎都没有这个问题.我发现很难相信,至少在某些时候,某人不会对此感到好奇.
In addition, this was really supposed to be a question about finding local functions in general and there doesn't seem to be a question about it anywhere else on StackOverflow. I find it hard to believe that at SOME POINT someone won't, at the very least, be curious about to do so.
我一开始很犹豫是否提供任何代码,因为我只是想修改一个主意,但是我想要实现的实际目标完全是这个问题的第二要务.
I was hesitant to provide any code in the first place because I'm just tinkering with an idea, but the actual goal I'm trying to accomplish is secondary to the question altogether.
推荐答案
好的,我有一个解决方案.但这真的很可怕.它涉及从您的方法创建具有 specific 类型的委托,然后使用该委托来找到 generic 方法,然后构造另一个特定方法并调用它.
Okay, I've got a solution. But it's really horrible. It involves creating a delegate from your method with a specific type, then using that to find the generic method, then constructing another specific method and invoking it.
所以我们从UseAs<int>
到UseAs<T>
到UseAs<the-type-we-want>
.
在许多方面它可能都犯了可怕的错误,但是它对我测试过的非常有限的样本有效.
It could go horribly wrong in many ways, but it works for the very limited sample I've tested:
// DISCLAIMER: THIS CODE IS FAIRLY HACKY, AND MAY WELL FAIL IN WEIRD
// SITUATIONS. USE WITH EXTREME CAUTION AND LOTS OF TESTS!
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
HandleResponse("foo", typeof(string));
}
static void HandleResponse(object data, Type type)
{
string local = "This was a local variable";
void UseAs<T>(T obj)
{
Console.WriteLine($"Object is now a: {typeof(T)}:");
// Proof that we're capturing the target too
Console.WriteLine($"Local was {local}");
}
InvokeHelper(UseAs, data, type);
}
// This could be in any class you want
static void InvokeHelper(Action<int> int32Action, object data, Type type)
{
// You probably want to validate that it really is a generic method...
var method = int32Action.Method;
var genericMethod = method.GetGenericMethodDefinition();
var concreteMethod = genericMethod.MakeGenericMethod(new[] { type });
concreteMethod.Invoke(int32Action.Target, new[] { data });
}
}
这篇关于反思:如何在C#7.0中查找和调用本地功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!