这是为什么通用在编译时解决? [英] why is this generic not resolved at compile time?

查看:130
本文介绍了这是为什么通用在编译时解决?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的代码。我期待它打印:

  A 
B
C
DONE

相反,它打印

 <$ C $ ç>点
P
P
DONE



为什么?



更新结果
我不要求对周围的工作方案。我想知道为什么发生这种情况。我以为泛型是在编译时解析。从我可以告诉它应该能够解决这些在编译时的正确方法,但显然它不是我不明白为什么。我在找原因,而不是一个变通的解决方案的说明



这里是代码:

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

命名空间ConsoleApplication50
{
级父
{
公共字符串字段名{获得;组; }
公共字符串ID {搞定;组; }
}

类ChildA:家长
{
公共字符串fieldValue方法{搞定;组; }
}

类ChildB:家长$​​ B $ B {
公众的DateTime?启动{搞定;组; }
公众的DateTime?结束{搞定;组; }
}

类ChildC:家长
{
公众的ICollection<串GT;值{搞定;组; }
}
类节目
{
void验证< T>(父项),其中T:家长
{
如果(产品T)
验证(项目作为T);
}
void验证(ChildA过滤器)
{
Console.WriteLine(A);
}

void验证(ChildB过滤器)
{
Console.WriteLine(B);
}

void验证(ChildC过滤器)
{
Console.WriteLine(C);
}

void验证(家长过滤器)
{
Console.WriteLine(P);
//什么也不做的占位符,使代码编译
}

ArgumentException的失败(父过滤器,字符串消息)
{
返回新的ArgumentException(消息,filter.FieldName);
}

无效的run()
{
无功名单=新名单,LT;家长和GT; {
新ChildA(),新ChildB(),新ChildC()};
&验证LT; ChildA>(名单[0]);
&验证LT; ChildB>(名单[1]);
&验证LT; ChildC>(名单[2]);
}
公共静态无效的主要()
{
新计划()的run()。
Console.WriteLine();
Console.WriteLine(DONE);
到Console.ReadLine();
}
}
}


解决方案

泛型是一个运行时的概念。这是从C ++模板,这是一个编译时的概念的主要区别



在该方法验证< T> T 总是未知的在编译时,甚至当调用者明确指定。在的事情验证< T> 知道 T 是从<$下降C $ C>父。



具体而言,仿制药不能用来生成代码。什么你想在C将工作++,因为当C ++看到一个调用验证< ClassA的> ,它实际上重新编译验证< T> ,所以模板成为一种代码生成的。在C#中,验证< T> 只编译一次,所以仿制药不能用来作为一种代码生成



在C ++中,调用验证< ClassA的> 将实例在编译时模板



下。 C#中,调用验证< ClassA的方式> 将instatiate在运行时泛型方法


I have the following code. I expect it to print:

A
B
C
DONE

instead it prints

P
P
P
DONE

why?

UPDATE
I'm not asking for a work around solution. I want to know why this is happening. I thought generics were resolved at compile time. From what I can tell it should be able to resolve these to the proper methods at compile time, but apparently it is not and I do not understand why. I am looking for an explanation of why, not a work around solution.

here is the code:

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();
        }
    }
}

解决方案

Generics are a run-time concept. This is their primary difference from C++ templates, which are a compile-time concept.

Within the method Validate<T>, T is always unknown at compile-time, even when explicitly specified by the caller. The only thing Validate<T> knows about T is that it descends from Parent.

More specifically, generics cannot be used to generate code. What you're trying would work under C++ because when C++ sees a call to Validate<ClassA>, it actually recompiles Validate<T>, so templates become a kind of code generation. Under C#, Validate<T> is only compiled once, so generics cannot be used as a kind of code generation.

Under C++, the call to Validate<ClassA> will instantiate the template at compile-time.

Under C#, the call to Validate<ClassA> will instatiate the generic method at run-time.

这篇关于这是为什么通用在编译时解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆