6

假设我已将 Func 定义如下:

Func<MyClass, object> f = o => o.StringProperty;

或者

Func<MyClass, object> f = o => o.Property.SomeMethod();

有没有办法在不专门调用它的情况下获得实际的返回类型?

4

3 回答 3

5

您可以像这样获得返回类型:

f.Method.ReturnType

但这会给你返回 type object。如果您想获取MethodorString或派生自 的东西,object除非您调用该方法,否则您将无法获得信息。

实际上你可以,但这意味着你必须反汇编方法核心,然后分析它以查看方法可以返回什么。但即便如此,也可能有许多不同的返回类型。

所以答案是:如果你想知道它返回一个对象,那么是的,你可以,否则不值得麻烦,最好找到另一种方法来做你需要的事情。

于 2013-07-24T14:36:48.917 回答
2

由于您Func<MyClass, object>在运行时从其他来源检索这些委托,因此类型信息基本上丢失了。

相反,在定义这些函数的地方,您可以让调用者通过利用LINQ 表达式API将类型信息基本上编码在包装的委托中(编辑:愚蠢的我,此时要简单得多;我们已经有了通用编译时间信息):

public class MyClassDelegate
{
    private readonly Func<MyClass, object> Function;

    public Type ReturnType { get; private set; }

    private MyClassDelegate(Func<MyClass, object> function, Type returnType)
    {
        this.Function = function;
        this.ReturnType = returnType;
    }

    public object Invoke(MyClass context)
    {
        return Function(context);
    }

    public static MyClassDelegate Create<TReturnType>(Func<MyClass, TReturnType> function)
    {
        Func<MyClass, object> nonTypedFunction = o => function(o);
        return new MyClassDelegate(nonTypedFunction, typeof(TReturnType));
    }
}

(也可以创建一个派生的泛型MyClassDelegate<TReturnType> : MyClassDelegate类来解决Create方法中的一些愚蠢问题,或者避免值类型装箱,或者在编译时提供返回类型信息,甚至通过反映任何MyClassDelegate<TReturnType>内容。)

定义委托而不是直接使用 a 的调用者Func<MyClass, object>将使用此类并将其委托定义为:

MyClassDelegate f1 = MyClassDelegate.Create(o => o.StringProperty);
MyClassDelegate f2 = MyClassDelegate.Create(o => o.Property.SomeMethod());

您的 API 需要一个MyClassDelegate,您可以使用它轻松访问它们的类型:

Console.WriteLine(f1.ReturnType.FullName); //string
Console.WriteLine(f2.ReturnType.FullName); //whatever `SomeMethod()` is declared to return

最后,您仍然可以调用委托甚至创建Func<MyClass, object>委托:

f1.Invoke(myClassInstance);
Func<MyClass, object> f3 = f1.Invoke;
于 2013-07-24T15:18:51.747 回答
1

您可以通过使用泛型方法使编译器推断类型参数来做一些接近此的事情:

static Func<T1, R> Infer<T1, R>(Func<T1, R> f) { return f; }

接着:

var func = Infer((string s) => s.Length);

这会将返回类型编码为func编译时的类型。

当然,对于更普遍适用的解决方案,您将需要一堆重载Infer来覆盖ActionFunc带有一个、两个、三个等参数。

然后,如果您想在运行时获取返回类型,对于任何类型的Funcfunc.Method.ReturnType都像 ppetrov 已经指出的那样简单。

于 2013-07-24T14:36:30.953 回答