代码之家  ›  专栏  ›  技术社区  ›  Armen Tsirunyan

泛型方法采用KeyValuePair。如何将调用转发到使用密钥类型的正确重载?

  •  7
  • Armen Tsirunyan  · 技术社区  · 6 年前
     class Program
        {
            static void Main(string[] args)
            {
    
            }
    
            void DoSomething(int a)
            {
                Console.WriteLine("int");
            }
            void DoSomething(char a)
            {
                Console.WriteLine("char");
            }
            void DoSomething<T, U>(KeyValuePair<T, U> a)
            {
                DoSomething(a.Key);
            }
        }
    

    我有一个第三方程序集,它有一个巨大的结构,其中包含许多不同类型的成员。我需要从结构中获取一些值并处理它们。所以我为不同的类型写重载。我知道我需要对int、chars等做什么,如果某个值是一个键值对,我知道我只需要像处理原语值一样处理这个键。上面的代码是我失败的尝试。问题是C编译器抱怨它无法确定要调用哪个重载 a.Key

    4 回复  |  直到 6 年前
        1
  •  3
  •   Selman Genç    6 年前

    一个很难的方法是 a.Key 要动态:

    DoSomething((dynamic)a.Key);
    

        2
  •  3
  •   mjwills Myles McDonnell    6 年前

    如果你100%确信 T int char -那么 dynamic 是一种需要考虑的方法:

    static void DoSomething<T, U>(KeyValuePair<T, U> a)
    {
        dynamic bob = a.Key;
        DoSomething(bob);
    }
    
        3
  •  3
  •   Damien_The_Unbeliever    6 年前

    dynamic 方法是它给你一个运行时错误。让泛型代码进行编译,但由于类型不匹配而产生运行时错误,对我来说总感觉像是一个“谎言”——如果不能将其表示为类型参数约束,并且编译器编译失败,那么就不应该编写泛型方法。

    我将提供两种方法:

        void DoSomething<U>(KeyValuePair<int, U> a)
        {
            DoSomething(a.Key);
        }
        void DoSomething<U>(KeyValuePair<char, U> a)
        {
            DoSomething(a.Key);
        }
    

    现在你只能提供 KeyValuePair 我们知道如何正确地处理这些错误,其他的一切都会返回到生成编译时错误。我更喜欢有点多余的 1 在编译时获取错误。


    当然,在上面,这些方法的实用性有点可疑,但是在一个更大的代码库中,您仍然可以抽象出 一些 将函数转换为私有泛型方法 DoSomething 方法遵循。


    1 剂量测定 方法不同,因为重载解析将产生不同的结果。

        4
  •  1
  •   Grax32    6 年前

    从C#7.1开始,您可以使用 is dynamic 因为抛出的错误将是运行时错误而不是编译时错误,但是它消除了使用动态的CLR开销。

    private void DoSomething<T, U>(KeyValuePair<T, U> a)
    {
        if (a.Key is int keyInt)
        {
            DoSomething(keyInt);
        }
        else if (a.Key is char keyChar)
        {
            DoSomething(keyChar);
        }
        else
        {
            throw new Exception("Unable to DoSomething to a.Key");
        }
    }
    

    同样的事情,但是更漂亮因为 switch 声明。

    private void DoSomething<T, U>(KeyValuePair<T, U> a)
    {
        switch (a.Key)
        {
            case int keyInt:
                DoSomething(keyInt);
                break;
            case char keyChar:
                DoSomething(keyChar);
                break;
            default:
                throw new Exception("Unable to DoSomething to a.Key");
        }
    }