为什么这个泛型在编译时没有得到解决?

Cha*_*ert 4 c# generics

我有以下代码.我希望它打印:

A
B
C
DONE
Run Code Online (Sandbox Code Playgroud)

相反它打印

P
P
P
DONE
Run Code Online (Sandbox Code Playgroud)

为什么?

更新
我不是要求解决方案.我想知道为什么会这样.我认为泛型在编译时得到了解决.从我可以告诉它应该能够在编译时将这些解析为正确的方法,但显然它不是,我不明白为什么.我正在寻找解释原因的解释,而不是解决方案.

这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication50
{
    class Parent
    {
        public string FieldName { get; set; }
        public string Id { get; set; }
    }

    class ChildA : Parent
    {
        public string FieldValue { get; set; }
    }

    class ChildB : Parent
    {
        public DateTime? Start { get; set; }
        public DateTime? End { get; set; }
    }

    class ChildC : Parent
    {
        public ICollection<string> Values { get; set; }
    }
    class Program
    {
        void Validate<T>(Parent item) where T : Parent
        {
            if (item is T)
                Validate(item as T);
        }
        void Validate(ChildA filter)
        {
            Console.WriteLine("A");
        }

        void Validate(ChildB filter)
        {
            Console.WriteLine("B");
        }

        void Validate(ChildC filter)
        {
            Console.WriteLine("C");
        }

        void Validate(Parent filter)
        {
            Console.WriteLine("P");
            // do nothing placeholder so the code will compile
        }

        ArgumentException Fail(Parent filter, string message)
        {
            return new ArgumentException(message, filter.FieldName);
        }

        void Run()
        {
            var list = new List<Parent> {
                new ChildA(), new ChildB(), new ChildC() };
            Validate<ChildA>(list[0]);
            Validate<ChildB>(list[1]);
            Validate<ChildC>(list[2]);
        }
        public static void Main()
        {
            new Program().Run();
            Console.WriteLine();
            Console.WriteLine("DONE");
            Console.ReadLine();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 11

泛型是一个运行时概念.这是它们与C++模板的主要区别,C++模板是一个编译时的概念.

在该方法中Validate<T>,在编译时始终T未知的,即使在调用者明确指定时也是如此.的唯一的事情Validate<T>知道T的是,它的下降Parent.

更具体地说,泛型不能用于生成代码.你正在尝试的是在C++下工作,因为当C++看到一个调用时Validate<ClassA>,它实际上重新编译Validate<T>,因此模板成为一种代码生成.在C#下,Validate<T>只编译一次,因此泛型不能用作一种代码生成.

在C++下,调用Validate<ClassA>将在编译时实例化模板.

在C#下,调用Validate<ClassA>将在运行时实例化泛型方法.

  • 值得注意的是,即使没有Reflection,在.NET中也有可能有一个方法,当传入一个由字母X和Y组成的字符串(例如"XYXXYXY")时,会调用类型为"X <Y"的泛型方法<X <X <Y <X <Y <fnord >>>>>>>`,有效地证明单个.NET程序可能使用的不同类的数量基本上是无限的 - 这种情况与C++有很大不同每个不同类型都需要有与之关联的代码. (2认同)

dtb*_*dtb 5

过载分辨率在编译时执行,而不是在运行时执行.

通常的解决方案是在这里使用简单的虚拟调度:

class Parent
{
    public virtual  void Validate() { Console.WriteLine("P"); }
}

class ChildA : Parent
{
    public override void Validate() { Console.WriteLine("A"); }
}

class ChildB : Parent
{
    public override void Validate() { Console.WriteLine("B"); }
}

void Run()
{
    var list = new List<Parent> { new ChildA(), new ChildB() };
    list[0].Validate(); // prints "A"
    list[1].Validate(); // prints "B"
}
Run Code Online (Sandbox Code Playgroud)