在 C# 中,如何根据输入泛型类型的超类型分派到 2 个不同的泛型函数?

问题描述 投票:0回答:1

考虑以下代码:


    public static class TypeChecker
    {
        public static string CheckType<T>()
        {
            return typeof(T).IsValueType ? HandleValueType<T>() : HandleReferenceType<T>();
        }

/*
compilatioon error looks like this:
1>Pure.cs(9,44): Error CS0453 : The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'TypeChecker.HandleValueType<T>()'
1>Pure.cs(9,67): Error CS0452 : The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'TypeChecker.HandleReferenceType<T>()'
*/

        private static string HandleValueType<T>() where T : struct
        {
            return $"This is a value type (struct): {typeof(T).Name}";
        }

        private static string HandleReferenceType<T>() where T : class
        {
            return $"This is a reference type: {typeof(T).Name}";
        }
    }

编译器无法将

typeof
与 2 个私有函数施加的约束关联起来,这解释了错误。最简单的方法是什么?

我正在使用 C# 9.x,但更高版本的解决方案也将受到赞赏

c# generics pattern-matching multiple-dispatch
1个回答
0
投票

您可以使用静态泛型类、其中的字段和表达式树来施展一些魔法:

public static class TypeChecker
{
    private static class TypeCheckerInternal<T>
    {
        private static Func<string> _handle;
        static TypeCheckerInternal()
        {
            var handleReferenceType = typeof(TypeChecker)
                .GetMethod(nameof(TypeChecker.HandleReferenceType), BindingFlags.Static | BindingFlags.NonPublic);  
            var handleValueType = typeof(TypeChecker)
                .GetMethod(nameof(TypeChecker.HandleValueType), BindingFlags.Static | BindingFlags.NonPublic);
            var method = typeof(T).IsValueType
                ? handleValueType.MakeGenericMethod(typeof(T))
                : handleReferenceType.MakeGenericMethod(typeof(T));
            var expression = Expression.Lambda<Func<string>>(Expression.Call(method));
            _handle = expression.Compile();
        }

        public static string Handle() => _handle();
    }
    public static string CheckType<T>()
    {
        return TypeCheckerInternal<T>.Handle();
    }

    private static string HandleValueType<T>() where T : struct
    {
        return $"This is a value type (struct): {typeof(T).Name}";
    }

    private static string HandleReferenceType<T>() where T : class
    {
        return $"This is a reference type: {typeof(T).Name}";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.