使用反射和运行时已知的类型调用 Func 对象

Invoke a Func object using reflection and a Type that's known at runtime

我一直在努力解决这个问题。我在 SO 上浏览过的各种类似(但不完全相同)的问题并没有完全把我带到我想要的地方。

我有一个 Type 和一个 Func<string, (bool, T)> 类型的对象,其中 T 与 Type 匹配。我希望能够通过反射或其他方式调用它的 Invoke 方法。

我在运行时有一些Type

Type type;

我记忆中有 Func,但作为 object:

object func;

func 的底层类型就是我之前描述的。例如,如果 type 表示 DateTime,那么 func 的基础类型将是:

Func<string, (bool, DateTime)>

但是 type 在运行时可以是任何东西,所以如果它是一个 int,那么 func 现在将是一个

Func<string, (bool, int)>

我如何利用我在运行时拥有正确类型这一事实来调用我的函数?我假设我必须使用某种反射,但对它的理解还不够深入。

非常感谢任何帮助。

总的来说,我对反思还很陌生,但我发现它非常有趣,但对某些事情来说却相当困难。如果您有任何关于阅读的建议或任何其他关于如何更好地学习反思的技巧,那也很好!

EDIT/UPDATE 想了想:

只使用 dynamic 并以这种方式调用 Invoke 会更好吗?看起来它会工作得很好,但随之而来的问题是,为什么你会经历更困难或更长时间的设置反射来调用某些东西的过程,而不是简单的动态调用。

无论如何,我仍然想知道这将如何使用反射,看看会很有趣

如果你知道像 Func 这样的函数的类型,你可以直接转换它,如下所示

 private static void InvokeFunctionDynamically<T>(T data)
    {            

        //1. Define the delegate 
        Func<string, bool, T> genericFunction = (name, isEnabled) =>
        {
            if(isEnabled)
            {
                return data;
            }

            return default(T);
        };

        // 2. demonstrate that the delegate is retrieved at the run time as an object
        object runtimeObject = genericFunction;


        //3. Cast it directly to the delegate type
        var result =((Func<string, bool, T>) runtimeObject)("hello", true);

        Console.WriteLine($"Result {result}");
    }

结果如下:

题目错误"artificial"。是的,你可以使用反射,是的,你可以使用动态...但是 "right" 要做的是将签名更改为:

public (bool, object) SomeMethod(string par)

代表:

Func<string, (bool, object)>

public bool SomeMethod(string par, out object obj)

委托(注意不能用Func<,>/Action<,>):

public delegate bool MyDelegate(string par, out object obj)

使用此签名,您不需要反射来调用方法,也不需要反射来解析 return。您的 return 值/outobject 内的方法装箱。性能还是比用反射好。

其他半好的候选人可能是:

Tuple<bool, type> SomeMethod(string par)

(其中 type 是您的更改类型)

代表:

Func<string, object>

Func<string, dynamic>

通过使用 Tuple<bool, type> 你会得到一些东西:Tuple<> 是一个引用类型,并且委托在 return 类型中是逆变的,所以你可以 "unify" 它们到object/dynamicdynamic 是一个 object,其中包含程序员将尝试对 object 执行 "bad things" 的 C# 编译器的一些信息)

现在您必须使用反射/dynamic 来访问 Tuple<>.Item1Tuple<>.Item2

使用反射和使用dynamic的区别在于,使用反射可以"cache"通过type部分反射,从而加快后面使用type 方法,使用 dynamic 这不会发生。