C# 为什么不是';难道没有一种隐含的类型吗?
我想我理解为什么这个小型C#控制台应用程序无法编译:C# 为什么不是';难道没有一种隐含的类型吗?,c#,C#,我想我理解为什么这个小型C#控制台应用程序无法编译: using System; namespace ConsoleApp1 { class Program { static void WriteFullName(Type t) { Console.WriteLine(t.FullName); } static void Main(string[] args) {
using System;
namespace ConsoleApp1
{
class Program
{
static void WriteFullName(Type t)
{
Console.WriteLine(t.FullName);
}
static void Main(string[] args)
{
WriteFullName(System.Text.Encoding);
}
}
}
编译器引发CS0119错误:“Encoding”是在给定上下文中无效的类型。我知道我可以使用typeof()
操作符从类型对象的名称生成类型对象:
...
static void Main(string[] args)
{
WriteFullName(typeof(System.Text.Encoding));
}
...
一切都按预期进行
但对我来说,typeof()
的使用似乎总是有些多余。如果编译器知道某个标记是对给定类型的引用(如错误CS0119所示),并且它知道某个赋值的目标(无论是函数参数、变量还是其他)需要对给定类型的引用,那么为什么编译器不能将其视为隐式typeof()
调用
或者,编译器完全有能力执行这一步骤,但由于可能产生的问题,它被选择不执行。这是否会导致我现在无法想到的任何歧义/易读性问题
如果编译器知道某个标记是对给定类型的引用(如错误CS0119所示),并且它知道某个赋值的目标(无论是函数参数、变量还是其他)需要对给定类型的引用,为什么编译器不能将其作为隐式typeof()调用
首先,您的建议是编译器同时考虑“从内到外”和“从外到内”。也就是说,为了使您建议的功能正常工作,编译器必须推断表达式System.Text.Encoding
引用了一个类型,并且上下文(调用writevelname
)需要一个类型我们如何知道上下文需要类型?writeFileName
的解析需要重载解析,因为可能有一百个解析,并且可能只有一个解析将类型
作为该位置的参数
所以现在我们必须设计重载解析来识别这个特定的情况。过载解决已经够难了。现在还要考虑对类型推断的影响。
C#的设计使得在绝大多数情况下,您不需要进行双向推理,因为双向推理既昂贵又困难。我们使用双向推理的地方是lambdas,我花了一年的大部分时间来实现和测试它。在lambdas上获得上下文敏感推理是使LINQ工作所必需的一个关键特性,因此获得正确的双向推理是值得的
此外:类型为什么特别?说objectx=typeof(T)是完全合法的代码>所以不应该对象x=int代码>在您的提案中是否合法?假设类型C
具有用户定义的从type
到C
的隐式转换;不应该C=string代码>合法吗
但是让我们暂时搁置一下,考虑一下你的建议的其他优点。例如,您打算对此做些什么
class C {
public static string FullName = "Hello";
}
...
Type c = C;
Console.WriteLine(c.FullName); // "C"
Console.WriteLine(C.FullName); // "Hello"
你觉得c==c
但是c.FullName!=C.全名
?编程语言设计的一个基本原则是,可以将表达式填充到变量中,变量的值的行为与表达式类似,但这里根本不是这样
你的建议基本上是,每一个引用类型的表达式都有不同的行为,这取决于它是被使用还是被分配的,这是非常令人困惑的
现在,您可能会说,好吧,让我们用一种特殊的语法来消除使用类型的情况与提到类型的情况之间的歧义,有这样一种语法。它是(T)类型的typeof
!如果我们想把T.FullName
看作T
是Type
我们说typeof(T).FullName
如果我们想把T
看作是查找中的限定符,我们说T.FullName
,现在我们已经清楚地消除了这些情况的歧义,而不必做任何双向推断
基本上,基本问题是类型不是C#中的第一类。有些事情只能在编译时对类型执行。没有:
Type t = b ? C : D;
List<t> l = new List<t>();
因为C.M
根本没有任何成员。所以这个问题消失了。我们从不说“好吧,C.M
可转换为Action
,Action
有一个方法Invoke
,所以让我们允许C.M.Invoke()
。这不会发生。同样,方法组不是第一类值。只有在它们转换为委托之后,它们才会成为第一类值
基本上,方法组被视为具有值但没有类型的表达式,然后可转换性规则确定哪些方法组可转换为哪些委托类型
现在,如果你要提出一个方法组,应该隐式地转换为<代码>方法信息> />代码,并在任何一个被期望为<代码>方法信息>代码的上下文中使用,那么我们就必须考虑它的优点。几十年来提出了一个建议:<代码>信息> <代码>操作符(发音为Foof)。“当然!)当给定一个方法组时,它将返回一个
MethodInfo
,当给定一个属性时,它将返回一个PropertyInfo
,以此类推,而该方案总是失败,因为设计工作太多,效益太少nameof
是实现该版本的最便宜的方法
一个你没有问但似乎有密切关系的问题:
您说过C.FullName
可能不明确,因为不清楚C
是类型还是C
类型。C#中是否存在其他类似的歧义
对!!考虑:
enum Color { Red }
class C {
public Color Color { get; private set; }
public void M(Color c) { }
public void N(String s) { }
public void O() {
M(Color.Red);
N(Color.ToString());
}
}
在这种情况下,巧妙地称为“颜色问题”,
enum Color { Red }
class C {
public Color Color { get; private set; }
public void M(Color c) { }
public void N(String s) { }
public void O() {
M(Color.Red);
N(Color.ToString());
}
}