这是为什么通用在编译时解决? [英] why is this generic not resolved at compile time?
问题描述
我有下面的代码。我期待它打印:
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屋!