如何模式匹配泛型类型

时间:2013-12-27 21:14:47

标签: c# generics

我想检测一种类型是否与某种类型模式匹配。在这种情况下,模式是Expression<Func<T, bool>>,其中T可以匹配任何类型(标准解释)。

鉴于这种模式,

Expression<Func<string, bool>> v;  //matches
Expression<string> v;  //doesn't match    
Expression<Func<string, string, bool>> v;  //doesn't match

我的策略是比较测试类型的FullName的开头是否与泛型类型的FullName匹配。如果是,请通过GetGenericArguments剥离图层,然后重复检查。第一次检查的代码:

Type testType;

Type firstCheck = (System.Linq.Expressions.Expression<>);
bool isExpression = testType.FullName.StartsWith(firstCheck.FullName);

这似乎有效,但相当丑陋。而且,它不是通用的解决方案;每个模式都需要自己的检查功能。有没有人有更好的解决方案?

一个相关的问题是如何最好地表达一种模式?

1 个答案:

答案 0 :(得分:5)

改为使用GetGenericTypeDefinition method

Type testType;

Type firstCheck = typeof(System.Linq.Expressions.Expression<>);
bool isExpression = 
    (testType.IsGenericType && testType.GetGenericTypeDefinition() == firstCheck)
    || (!testType.IsGenericType && testType == firstCheck);

更新

这是一个重复方法,用于检查类型是否匹配给定模式:

private static bool IsTypeCompatibile(Type pattern, Type test, Type placeholder)
{
    if (pattern == test || pattern == placeholder)
        return true;

    if(pattern.IsGenericType)
    {
        if (!test.IsGenericType || pattern.GetGenericTypeDefinition() != test.GetGenericTypeDefinition())
            return false;

        var patternGenericTypes = pattern.GetGenericArguments();
        var testGenericTypes = test.GetGenericArguments();

        return patternGenericTypes.Length == testGenericTypes.Length
            && patternGenericTypes.Zip(testGenericTypes, (p, t) => IsTypeCompatibile(p, t, placeholder)).All(x => x);

    }

    return false;
}

用法:

var pattern = typeof(Expression<Func<Placeholder, bool>>);

var type1 = typeof(Expression<Func<string, bool>>);
var type2 = typeof(Expression<string>);
var type3 = typeof(Expression<Func<string, string, bool>>);

Console.WriteLine(IsTypeCompatibile(pattern, type1, typeof(Placeholder)));
Console.WriteLine(IsTypeCompatibile(pattern, type2, typeof(Placeholder)));
Console.WriteLine(IsTypeCompatibile(pattern, type3, typeof(Placeholder)));

打印

True
False
False

当然,您需要定义Placeholder class:

public class Placeholder
{ }