C# 为什么条件方法的参数总是被检查类型?
在条件方法被编译掉的情况下,每次调用的参数仍然在编译时进行类型检查。这样做的动机是什么?例如:C# 为什么条件方法的参数总是被检查类型?,c#,conditional-attribute,C#,Conditional Attribute,在条件方法被编译掉的情况下,每次调用的参数仍然在编译时进行类型检查。这样做的动机是什么?例如: using System.Diagnostics; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { int x = 2; string st = ""; // thi
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int x = 2;
string st = "";
// this invocation compiles fine
ConditionalMethod(x, st);
// this invocation won't compile
ConditionalMethod(st, x);
}
[Conditional("condition")]
public static void ConditionalMethod(int x, string st) { }
}
}
需要说明的是,在这个上下文中没有定义条件符号“condition”,因此在编译产生的MSIL中省略了方法调用。这与规格定义一致,所以没有惊喜。想象一个更复杂的场景:
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ConditionalMethod(new Bar());
}
[Conditional("condition")]
public static void ConditionalMethod(Foo foo) { }
public class Foo { }
#if condition
public class Bar : Foo { }
#else
public class Bar { }
#endif
}
}
只有在定义了条件符号“condition”时,“ConditionalMethod”的调用才会包含在结果编译中。然而,在这种情况下,Bar实际上可以向上转换为Foo。如果编译器知道对“ConditionalMethod”的调用将被编译掉,那么它是否也应该知道,如果我们关心此方法的调用,那么此代码将是合法的?是的,这是一个精心设计的令人毛骨悚然的例子,但它有助于说明我的问题。我这样问是出于善意的好奇,因为这已经让我厌烦了很长一段时间了。请帮帮我,乔恩·斯基特。:) 想象一下这个代码
class Program
{
static void Main(string[] args)
{
int x = 2;
string st = "";
// this invocation compiles fine
Blah(x, st);
// this invocation won't compile
Blah(st, x);
}
[Conditional("condition")]
public static void Blah(int x, string st) { }
public static void Blah (string st, int x, int y) { }
public static void Blahh(string st, int x) { }
}
方法的签名是将调用关联到应调用的方法的关键部分。在知道条件属性是否适用之前,必须建立该关联。在上面的示例中,调用与任何方法都不匹配。编译器要想猜出你指的是什么废话(int,string),就必须有信心。但这只是猜测,因为签名的顺序不匹配(参数类型的顺序错误)。Blah(string,int,int)也非常接近-您刚刚忘记了一个参数。而且Blahh(string,int)也很接近-您只是在名称中输入了一个错误
有关类似的示例,请参见(谁知道这些东西)
因此,参数必须在调用时定义良好,
即使电话将被删除。事实上,这个电话不可能被取消
删除,除非参数存在
后来
条件编译指令的效果在lex时间发生;
lexer将移除的#if块中的任何内容视为
评论。就好像你只是简单地删除了
块,并将其替换为空白。但是删除呼叫站点
依赖条件属性发生在语义分析时;
执行语义分析所需的一切都必须
出席
想象一下这个代码
class Program
{
static void Main(string[] args)
{
int x = 2;
string st = "";
// this invocation compiles fine
Blah(x, st);
// this invocation won't compile
Blah(st, x);
}
[Conditional("condition")]
public static void Blah(int x, string st) { }
public static void Blah (string st, int x, int y) { }
public static void Blahh(string st, int x) { }
}
方法的签名是将调用关联到应调用的方法的关键部分。在知道条件属性是否适用之前,必须建立该关联。在上面的示例中,调用与任何方法都不匹配。编译器要想猜出你指的是什么废话(int,string),就必须有信心。但这只是猜测,因为签名的顺序不匹配(参数类型的顺序错误)。Blah(string,int,int)也非常接近-您刚刚忘记了一个参数。而且Blahh(string,int)也很接近-您只是在名称中输入了一个错误
有关类似的示例,请参见(谁知道这些东西)
因此,参数必须在调用时定义良好,
即使电话将被删除。事实上,这个电话不可能被取消
删除,除非参数存在
后来
条件编译指令的效果在lex时间发生;
lexer将移除的#if块中的任何内容视为
评论。就好像你只是简单地删除了
块,并将其替换为空白。但是删除呼叫站点
依赖条件属性发生在语义分析时;
执行语义分析所需的一切都必须
出席
如果参数类型与条件方法的定义不匹配,编译器如何知道您指的是具有该名称和签名的方法?如果方法没有重载,则不存在歧义,编译器事实上应该知道您引用的是哪个方法。但是这是一个我没有想到的好例子,对于重载的例子来说似乎是合理的。你在这里的建议是,如果方法组有一个元素,那么语言有一组规则,如果没有,那么语言有另一组规则。这真是个坏主意。这意味着对程序进行小的更改可能会导致重载解析结果发生大的变化,这不利于编写易于修改的程序。更一般地说,C#不是一种“猜测你的意思并希望得到最好的”语言。它不是一种“试图找出程序可以工作的任何方式,并使其工作”的语言。C#的态度是你希望编译器找到你的bug,如果一个程序看起来像bug,那么它应该告诉你。@EricLippert,谢谢你的回答!我还读了你关于条件编译和条件属性的博文。重载解析部分很有意义,我很欣赏。如果参数类型与条件方法的定义不匹配,编译器如何知道您指的是具有该名称和签名的方法?如果方法没有重载,那么就没有歧义,事实上,编译器应该知道您引用的是哪个方法。但是这是一个我没有想到的好例子,对于重载的例子来说似乎是合理的。你在这里的建议是,如果方法组有一个元素,那么语言有一组规则,如果没有,那么语言有另一组规则。这真是个坏主意。这意味着对程序进行小的更改可能会导致重载解析结果发生大的变化,这不利于编写易于修改的程序。更一般地说,C#不是一种“猜测你的意思并希望得到最好的”语言。它不是一种“试图找出程序可以工作的任何方式,并使其工作”的语言。C#的态度是希望编译器