有没有办法获取 typeof Func<T, bool>?

8

简短版:

我们可以使用以下方式获取 Func<T,T> 的类型:

typeof(Func<,>) 

但如果我想要获取 Func<T, bool> 的类型,我该使用什么?或者说这样做可能吗?很明显,以下代码无法编译:

typeof(Func<, bool>)

简化版:

假设有以下情景,我有两个类似的方法,并且想要使用反射获取第二个方法(Func<T, int>):

public void Foo<T>(Func<T, bool> func) { }

public void Foo<T>(Func<T, int> func) { }

我正在尝试这个:
 var methodFoo = typeof (Program)
            .GetMethods()
            .FirstOrDefault(m => m.Name == "Foo" &&
                        m.GetParameters()[0]
                        .ParameterType
                        .GetGenericTypeDefinition() == typeof (Func<,>));

但是由于 Func<T, bool>Func<T, int> 的泛型类型定义相同,因此它给我了第一个方法。为了解决这个问题,我可以执行以下操作:

var methodFoo = typeof (Program)
            .GetMethods()
            .FirstOrDefault(m => m.Name == "Foo" &&
                        m.GetParameters()[0]
                        .ParameterType
                        .GetGenericArguments()[1] == typeof(int));

我找到了正确的方法,但我不喜欢这种方式。对于更复杂的情况来说,这似乎是一种负担。我想做的是获取Func<T,bool>类型,就像我上面失败的尝试一样,然后不使用Linq而是使用GetMethod这个重载并进行以下操作:

var methodFoo = typeof (Program)
            .GetMethod("Foo", 
            BindingFlags.Public | BindingFlags.Instance,
            null, 
            new[] {typeof (Func<, bool>)}, // ERROR typeof(Func<,>) doesn't work either
            null);

注意:当然,Func<T,T>只是一个例子,问题不特定于任何类型。

1
+1 好问题!我们需要Jon Skeet在哪里?哈哈 - Felipe Oriani
1个回答

6
抱歉,您无法为部分绑定的泛型类型构建System.Type对象。您所做的方式(即使用GetGenericArguments()[1] == typeof(int))是正确的方法。
如果您需要在多个地方重复使用它,可以构建一个帮助程序扩展方法,该方法接受一个泛型类型定义和一个System.Type对象数组,并返回true,如果存在匹配项:
static bool IsGenericInstance(this Type t, Type genTypeDef, params Type[] args) {
    if (!t.IsGenericType) return false;
    if (t.GetGenericTypeDefinition() != genTypeDef) return false;
    var typeArgs = t.GetGenericArguments();
    if (typeArgs.Length != args.Length) return false;
    // Go through the arguments passed in, interpret nulls as "any type"
    for (int i = 0 ; i != args.Length ; i++) {
        if (args[i] == null) continue;
        if (args[i] != typeArgs[i]) return false;
    }
    return true;
}

现在,您可以将代码重写为以下内容:
var methodFoo = typeof (Program)
    .GetMethods()
    .FirstOrDefault(m => m.Name == "Foo" &&
        m.GetParameters()[0]
            .ParameterType
            .IsGenericInstance(typeof(Func<,>), null, typeof(bool))
    );

如果我使用methodFoo.GetParameters()[0].ParameterType,我得到的是Func<T, int>类型,所以它肯定会在某个地方被构造出来。

上面的T类型是您的泛型方法Foo的泛型类型参数。由于它不是“任意类型”,因此如果您希望可以构造此类型:

var typeT = methodFoo.GetGenericArguments()[0];
var funcTbool = typeof(Func<,>).MakeGenericType(typeT, typeof(bool));

需要注意的是,typeT被限定在特定泛型方法中,使得funcTbool类型不适合于在多个独立的泛型方法中搜索。

如果T是该方法所属类的类型参数,则可以这样写:

class FooType<T> {
    public void Foo(Func<T, bool> func) { }
    public void Foo(Func<T, int> func) { }
}

您可以基于 FooType<> 的泛型类型参数构建一个 funcTbool,并在不同的 Foo(...) 方法的签名中进行搜索。


如果我使用methodFoo.GetParameters()[0].ParameterType,我会得到Func<T, int>类型,所以它肯定在某个地方被构造了。我想也许可以直接得到它。 - Selman Genç
@Selman22 这是一个公正的观察 - 看一下编辑。 - Sergey Kalinichenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接