代码之家  ›  专栏  ›  技术社区  ›  CanisLupus

接收List<T>的C#泛型方法不会为实际类型的T调用重载方法(首选泛型方法)[duplicate]

  •  3
  • CanisLupus  · 技术社区  · 6 年前

    我有一个C代码示例:

    class Stuff { }  // empty class
    
    void Main()
    {
        var list = new List<Stuff> {
            new Stuff(),
            new Stuff()
        };
        Fun(list);
    }
    
    void Fun<T>(List<T> a)
    {
        Debug.Log("called List<T> Fun");
        foreach (T t in a) {
            Fun(t);
        }
    }
    
    void Fun(Stuff a)
    {
        Debug.Log("called Stuff Fun");
    }
    
    void Fun<T>(T a)
    {
        Debug.Log("called T Fun");
    }
    

    调用Main()以打印结束:

    called List<T> Fun
    called T Fun
    called T Fun
    

    我不明白为什么编译器能够调用 Fun<T>(List<T> a) Fun(Stuff a) ,这比 Fun<T>(T a) . 它在编译时不确定T是 Stuff typeof(T) 里面 按预期给出“东西”,但这不是任何证据。。。

    Fun(List<Stuff> a) 方法可以工作,但不受欢迎(对于项目中的列表,可能有很多不同的类型,并且所有列表的行为应该是相同的)。

    我试过寻找这个问题,但无法用我能找到的方式表达它。抱歉,如果有人问过这个问题(这很可能!)。

    1 回复  |  直到 6 年前
        1
  •  11
  •   Jon Skeet    6 年前

    关键是要明白这一点 void Fun<T>(List<T> a) 已编译 一旦 ,执行过载解析 一旦 . 每星期一次 T ,但只有一次。

    在编译此代码时,请考虑编译器的情况:

    void Fun<T>(List<T> a)
    {
        Debug.Log("called List<T> fun");
        foreach (T t in a) {
            Fun(t);
        }
    }
    

    特别是,请考虑调用 Fun(t)

    编译器对 T型 ,它是

    void Fun<T>(List<T> a)
    void Fun(Stuff a)
    void Fun<T>(T a)
    

    这个 适用的方法之一是最后一种方法 在调用代码中用作 T型 在我们调用的方法中,这很好。其他两种方法不适用,因为没有从 T型 List<TList> TList ),或来自 T型 Stuff .

    foreach (dynamic d in a) {
        Fun(d);
    }
    

    我个人不喜欢那样做,但是 在这种情况下你想怎么做就怎么做。另一方面,嵌套列表可能会变得很棘手-如果你 T型 是一个 List<int> ,那么你希望它会打电话来吗 Fun<List<int>>(list) Fun<int>(list) ? 老实说,我记不起这些规则,不知道哪一个“更好”,或者它是否模棱两可。