如何测试类型T是否实现了IParsable<T>接口?

4

.NET 7最近引入了接口IParsable,我想检查它是否存在。一些测试将返回true,如果T实现了 IParsable<T>,否则返回false

假设当T有一个名为Parse方法时,我想返回类型为T的对象,例如:

T ParseAs<T>(string s)
{
    if (typeof(IParsable<T>).IsAssignableFrom(typeof(T)))
    {
        return T.Parse(s);
    }
    else
    {
        //do something else...
    }
}

我希望检查T是否实现了IParsable<T>界面,并授予我对内部的ParseTryParse方法的访问权限。但是,我似乎无法将T用作IParsable的类型参数,而是收到以下异常消息:

CS0314
不能在泛型类型或方法“IParsable<TSelf>”中使用类型“T”作为类型参数“TSelf”。从“T”到“System.IParsable<T>”不存在装箱转换或类型参数转换。

如果我尝试使用is,我也会收到上述错误。
s is IParsable<T>

我该如何解决这个问题?


2
这个有帮助吗?https://dev59.com/6HRB5IYBdhLWcg3wz6Wd#503359 - DasKrümelmonster
这个编译通过了,但是我无法使用 T.Parse(s) - 你知道为什么吗? - Danatron1
1
IParsable递归定义,因此您需要在说出is IParsable<T>之前先确定TIParsable<T> - GSerg
我理解你的意思是,在我检查T是否为IParsable<T>之前,我必须知道T是IParsable<T>吗?这听起来像一个进退两难的局面。 - Danatron1
1个回答

4
要使用T.Parse()语法 - 您需要在编译时知道T实现了IParseable<T>。您唯一能在编译时确定这一点的方法是明确声明它:
T ParseAs<T>(string s) where T: IParsable<T> {
    return T.Parse(s, null);
}

如果只是输入了T而没有明确指定它是IParsable<T>类型,那么就无法使用T.Parse语法,需要一直使用反射。首先,您需要通过反射检查T是否实现了该接口,然后再次使用反射调用该静态方法:
T ParseAs<T>(string s) {
    var isParsable = typeof(T).GetInterfaces().Any(c => c.IsGenericType && c.GetGenericTypeDefinition() == typeof(IParsable<>));
    if (isParsable) {
        var parse = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public)
            .FirstOrDefault(c => c.Name == "Parse" && c.GetParameters().Length == 2 && c.GetParameters()[0].ParameterType == typeof(string) && c.GetParameters()[1].ParameterType == typeof(IFormatProvider));
        if (parse != null)
            return (T) parse.Invoke(null, new object[] { s, null });
    }

    return default(T);
}

当然,那样很丑陋,你很可能不想这么做。


反射方法是我在此更新之前使用的方法,我正在寻找一种更优雅的替代方法。谢谢你的答案 - 它完全回答了我的问题。 - Danatron1

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