【问题标题】:Is there a way to get typeof Func<T, bool>?有没有办法获得 typeof Func<T, bool>?
【发布时间】:2014-08-06 06:41:16
【问题描述】:

短版:

我们可以得到Func&lt;T,T&gt;的类型:

typeof(Func<,>) 

但是如果我想得到Func&lt;T, bool&gt;的类型怎么办,我应该使用什么,或者可以做什么?显然这不能编译:

typeof(Func<, bool>)

加长版:

考虑以下场景,我有两个类似的方法,我想使用反射获得第二个(Func&lt;T, int&gt;):

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&lt;T, bool&gt;Func&lt;T, int&gt; 的泛型类型定义是相等的,所以它给了我第一种方法。要解决此问题,我可以执行以下操作:

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

然后我得到了正确的方法,但我不喜欢这种方式。对于更复杂的情况,这似乎是一种开销。我想要做的是获得Func&lt;T,bool&gt; 的类型,就像我上面失败的尝试一样,然后我可以使用this overloadGetMethod 而不是使用Linq 并执行以下操作:

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

注意:当然Func&lt;T,T&gt; 只是一个例子,问题不针对任何类型。

【问题讨论】:

  • +1 好问题!当我们需要乔恩·斯基特时,他在哪里?哈哈

标签: c# generics reflection


【解决方案1】:

很遗憾,您不能为部分绑定的泛型类型构建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&lt;T, int&gt; 的类型,所以它肯定是在某个地方构建的

上面的类型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&lt;&gt; 的泛型类型参数构造funcTbool,并在不同Foo(...) 方法的签名中搜索它。

【讨论】:

  • 如果我使用methodFoo.GetParameters()[0].ParameterType,我得到的类型是Func&lt;T, int&gt;,所以它肯定是在某个地方构建的。我想也许可以直接得到它。
  • @Selman22 这是一个公平的观察 - 看看编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多